0

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.

Naveen
  • 1
  • 3

4 Answers4

1

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.

hc_dev
  • 8,389
  • 1
  • 26
  • 38
0

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.

Alexandr Ivanov
  • 389
  • 1
  • 5
  • 7
  • Thanks for the answer. I had set the ClassToMock instance (didn't show in the code, but, had mentioned it in the last line of the first post). – Naveen Apr 12 '20 at 13:57
0

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

sap
  • 54
  • 5
  • Thanks for the answer. I had set the ClassToMock instance (didn't show in the code, but, had mentioned it in the last line of the first post). – Naveen Apr 12 '20 at 13:57
-2

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.

Naveen
  • 1
  • 3
  • Great you solved and posted a self-answer Can you explain what you changed exactly, __adding the source__? So anyone having the same issue, can learn from you. – hc_dev Apr 12 '20 at 16:08
  • classToMock method had 4 parameters, out of which two were null in this case. So, I wrote a method in the ClassToMock ```method(param1, param2)``` and passed null for the 3rd and 4th parameter. This way I just avoided passing null from the TestClass method. You helped me passing isNull without overloading the method. Thanks. – Naveen Apr 12 '20 at 16:53