Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly match varargs in Mockito

People also ask

What is the rule for using varargs in java?

While using the varargs, you must follow some rules otherwise program code won't compile. The rules are as follows: There can be only one variable argument in the method. Variable argument (varargs) must be the last argument.

Is it good to use varargs in java?

Varargs are useful for any method that needs to deal with an indeterminate number of objects. One good example is String. format . The format string can accept any number of parameters, so you need a mechanism to pass in any number of objects.

What is argument matcher in Mockito?

Argument matchers are mainly used for performing flexible verification and stubbing in Mockito. It extends ArgumentMatchers class to access all the matcher functions. Mockito uses equal() as a legacy method for verification and matching of argument values.

What is doReturn in Mockito?

You can use doReturn-when to specify a return value on a spied object without making a side effect. It is useful but should be used rarely. The more you have a better pattern such as MVP, MVVM and dependency injection, the less chance you need to use Mockito. spy .


Mockito 1.8.1 introduced anyVararg() matcher:

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);

Also see history for this: https://code.google.com/archive/p/mockito/issues/62

Edit new syntax after deprecation:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);

A somewhat undocumented feature: If you want to develop a custom Matcher that matches vararg arguments you need to have it implement org.mockito.internal.matchers.VarargMatcher for it to work correctly. It's an empty marker interface, without which Mockito will not correctly compare arguments when invoking a method with varargs using your Matcher.

For example:

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
    @Override public boolean matches(Object varargArgument) {
        return /* does it match? */ true;
    }
}

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);

Building on Eli Levine's answer here is a more generic solution:

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;

import static org.mockito.Matchers.argThat;

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
        argThat(new VarArgMatcher(hamcrestMatcher));
        return null;
    }

    private final Matcher<T[]> hamcrestMatcher;

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
        this.hamcrestMatcher = hamcrestMatcher;
    }

    @Override
    public boolean matches(Object o) {
        return hamcrestMatcher.matches(o);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
    }

}

Then you can use it with hamcrest's array matchers thus:

verify(a).b(VarArgMatcher.varArgThat(
            org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));

(Obviously static imports will render this more readable.)


I have been using the code in Peter Westmacott's answer however with Mockito 2.2.15 you can now do the following:

verify(a).method(100L, arg1, arg2, arg3)

where arg1, arg2, arg3 are varargs.