Mockito 5.8.0 ambiquity with varargs

81 views Asked by At

if one has a method such as

Long foo(String... s)

that you wish to mock, you can do

Mockito.when(myMock.foo(ArgumentMatchers.any(String[].class))).thenReturn(Long.valueOf(1));

and if a call occurs such as

myMock.foo();
myMock.foo("hello");
myMock.foo("hello", "there");

it will work fine.

However if a call is made like

myMock.foo((String[]) null);

if fails, as the definition need be nullable(String[].class);

However, if you define it as nullable(String[].class); then

myMock.foo("Hello");

will fail to match as it thinks the type of the matcher is Object, as it calculates that based on the or(String[].class, isNull()) definition.

So it doesn't appear that all cases can be handled by the same syntax. Or am i wrong?

1

There are 1 answers

4
Lesiak On

You can easily adapt InstanceOf matcher to match null parameters.

Alternatively, you can use or matcher.

Please be aware that Mockito took the opposite direction: in 2.1.0 they changed any() not to accept null values.

class NullableInstanceOf extends InstanceOf {
    public static <T> T anyOrNull(Class<T> clazz) {
        Mockito.argThat(new NullableInstanceOf(clazz));
        return null;
    }

    public NullableInstanceOf(Class<?> clazz) {
        super(clazz);
    }

    @Override
    public boolean matches(Object actual) {
        return actual == null || super.matches(actual);
    }
}

Alternative matcher

AdditionalMatchers.or(ArgumentMatchers.isNull(String[].class), ArgumentMatchers.isA(String[].class)))

Note that alternative matcher is almost equivalent to the one used by nullable(String[].class), but uses isNull(String[].class) instead of isNull()

Matchcer used by nullable(String[].class)

AdditionalMatchers.or(ArgumentMatchers.isNull(), ArgumentMatchers.isA(String[].class)))

Test:

class Foo {
    Long foo(String... s) {
        return 5L;
    }
}


public class NullableInstanceOfTest {

    Foo myMock = Mockito.mock(Foo.class);

    @BeforeEach
    void init() {
        Mockito.when(myMock.foo(NullableInstanceOf.anyOrNull(String[].class))).thenReturn(1L);
    }

    @Test
    void matchesNoArgs() {
        Assertions.assertThat(myMock.foo()).isEqualTo(1L);
    }

    @Test
    void matchesOneArgs() {
        Assertions.assertThat(myMock.foo("hello")).isEqualTo(1L);
    }

    @Test
    void matchesTwoArgs() {
        Assertions.assertThat(myMock.foo("hello", "there")).isEqualTo(1L);
    }

    @Test
    void matchesNull() {
        Assertions.assertThat(myMock.foo((String[]) null)).isEqualTo(1L);
    }

}