One of the legacy tests uses Mockito argThat
to stub corresponding results in a loop.
It is passing if I decrease the number of iterations to 1 (numberOfItems = 1
, i.e. like if there's no loop).
As soon as it gets to the 2nd iteration, it errors out with NPE:
java.lang.NullPointerException: Cannot invoke "getValue()" because "arg" is null
The code is like this:
@Test
public void testMy() {
int numberOfItems = 2;
List<MyData> myDataList = getTestData(numberOfItems);
for (MyData md : myDataList) {
when(mockedService.someMethod(
argThat(arg -> Objects.equals(arg.getValue(), md.getMyValue())))) // NPE here on arg.getValue()
.thenReturn(getExpectedResult(md.getMyValue()));
}
List<MyData> resData = testService.methodUnderTest(myDataList);
// assert... resData list has all the expected items and values
}
The method being tested is similar to the following
public List<MyData> methodUnderTest(List<MyData> myDataList) {
myDataList.forEach(myData -> {
// ... some logic ...
myData.setResult(mockedService.someMethod(new MyRequest(myData.getMyValue())));
}
});
return myDataList;
}
But for the error case the method call is not even reached, coz NPE happens earlier in the unit test code.
Originally it was passing being used somewhat like this
when(mockedService.someMethod(
argThat(hasProperty("value", equalTo(md.getMyValue())))))
.thenReturn(getExpectedResult(md.getMyValue()));
however, I saw a recommendation to prefer comparing the objects directly, so I tried to re-write the stubbing as suggested, getting rid of those equalTo
and hasProperty
, bot now got into those NPE error :)
Any tips on what am I doing wrong, please? Thanks!!
When you call when(mockedService.someMethod(argThat(arg -> Objects.equals(arg.getValue(), md.getMyValue())))).thenReturn(getExpectedResult(md.getMyValue()));
the first time, the method becomes stubbed. When you call it a second time, the existing stub tries to match the second stubbing call. argThat
(and all other matcher methods) return null
, which makes the matcher of your existing stub throw.
Two potential solutions:
argThat(arg -> arg != null && ...)
to not match null inputswhen(mock.call(argThat(...))).thenReturn(result)
form – which actually calls the method! –, but switch to doReturn(result).when(mock).call(argThat(...))