简体   繁体   中英

Mockito when not returning the expected object

I am trying to return an expected value from a mocked method.

TestClass testClass = TestClass.getInstance();
ClassToMock classToMock = Mockito.mock(ClassToMock.class);
testClass.setClassToMock(classToMock);
ExpectedObject expectedObject = new ExpectedObject("1", "2", "3");
when(classToMock.method(ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean(),
                        ArgumentMatchers.any(A.class), ArgumentMatchers.any(B.class))
                .thenReturn(expectedObject);
testClass.invokeTestMethod();

The TestClass and invokeTestMethod are like below:

public class TestClass {

  private ClassToMock classToMock;

  public void invokeTestMethod() {
     ExpectedObject expectedObj1 = classToMock.method("A", "B", null, null);
     ::
     ::
     ExpectedObject expectedObj2 = classToMock.method("X", "Y", null, null);
     ::
     ::
     ExpectedObject expectedObj3 = classToMock.method("P", "Q", null, null);
     ::
     ::
  }

  public void setClassToMock(ClassToMock ctm) {
     this.classToMock = ctm;
  }
}

I have set the classToMock instance on the TestClass, to make sure that the TestClass works on the mock instance.

To make the issue clearer, the method call is happening on the mocked object (classToMock), but, the expected return value (ExpectedObject) is not coming.

Issue here: null does not match any(X.class) , so mocked value will not be returned

If null is passed as argument, then the two last argument matchers in place:

  • ArgumentMatchers.any(A.class)
  • ArgumentMatchers.any(B.class)

will not be matched .

See documentation of any(java.lang.Class) :

Matches any object of given type, excluding nulls . (marked bold to emphasize)

This is because since Mockito 2.1.0 internally try to evaluate the type (class) of the argument. And null is an empty reference, not pointing to an instanced object. No reference to an object, no class of that object can be evaluated:

null instanceOf A // will evaluate to `false`
null instanceOf B // will evaluate to `false`

See Is null check needed before calling instanceof?

Solution: use any() or isNull() to match null

To make the mocked methods be called inside, use an argument matcher that will match on null values passed.

In the first excerpt when method is called with method signature (String, bool, A, B) as parameter, while in the second excerpt is called method with signature (String, String, Object, Object). So in the second excerpt classToMock.method("A", "B", null, null) returns null.

you need to pass ClassToMock ro the TestClass for example in the constructor on in a set method. This way in the test you can pass your mock to test class and in the method invokeTestMethod the mock will be used. At the moment your not doing this, so method is called on the real object

Thanks to all who chose to help. I found the fix. In the TestClass, there was a call like this: ExpectedObject expectedObj1 = classToMock.method("A", "B", null, null); The two null parameters caused the issue. So, I overloaded the method inside the ClassToMock with the NON NULL parameters. After this change, the mock is working perfectly fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM