Search code examples
junitmockitospring-testspringmockito

any() vs any(Class.class) Mockito


I am not able to understand why below two tests are not giving the same result.

@Service
public class SomeManager{
    private final SomeDependency someDependency;
    
    @Autowired
    public SomeManager(SomeDependency someDependency){
        this.someDependency = someDependency;
    }
    
    public List<returnType> methodToTest(Arg arg){
        List<JsonObject> jo = someDependency.search(arg);
        return jo.stream().map(returnType::parse).collect(Collectors.toList());

    }
}

Test with any(). This Test pass.

@RunWith(SpringJUnit4ClassRunner.class)
public class TestMethodToTest(){
    @Test
    public void TestMethod(){
        SomeDependency someDependency = mock(SomeDependency.class);
        List<JsonObject> expected := \some valid list of JsonObject\
    
        // Here I used any() method.
        when(someDependency.search(any())).thenReturn(expected);
    
        SomeManager someManager = new SomeManager(someDependency);
        List<returnType> actual = someManager.methodToTest(any(Arg.class));
    
        assertArrayEquals(acutal.toArray(), expected.stream().map(returnType::parse).toArray());
        }
}

But since search(Arg arg) method of SomeDependency takes parameter of class Arg so I changed above test like this:

@RunWith(SpringJUnit4ClassRunner.class)
public class TestMethodToTest(){
    @Test
    public void TestMethod(){
        SomeDependency someDependency = mock(SomeDependency.class);
        List<JsonObject> expected := \some valid list of JsonObject\

        // Here I used any(Arg.class) method.
        when(someDependency.search(any(Arg.class))).thenReturn(expected);
    
        SomeManager someManager = new SomeManager(someDependency);
        List<returnType> actual = someManager.methodToTest(any(Arg.class));
    
        assertArrayEquals(acutal.toArray(), expected.stream().map(returnType::parse).toArray());
        }
}

This second test fails with output java.lang.AssertionError: array lengths differed, expected.length=1 actual.length=0.What's the possible reason behind this?

Note: The value expected.length=1 in output depends on what value is provided by the user as valid list of json objects in the test.


Solution

  • The difference stems from the fact that any matches null, while anyClass does not match null. See ArgumentMatchers javadoc:

    • any() Matches anything, including nulls and varargs.
    • any​(Class<T> type) Matches any object of given type, excluding nulls.

    You are passing null to your method under test here:

    List<returnType> actual = someManager.methodToTest(any(Arg.class));
    

    any() returns null which you pass to method under test.

    Note that using argument matchers this way is illegal - you should only call them inside calls to when and verify. You should pass a real instance of Arg to method under test.

    See Mockito javadoc

    Matcher methods like any(), eq() do not return matchers. Internally, they record a matcher on a stack and return a dummy value (usually null). This implementation is due to static type safety imposed by the java compiler. The consequence is that you cannot use any(), eq() methods outside of verified/stubbed method.