org.mockito.ArgumentMatcher Maven / Gradle / Ivy
Show all versions of mockito-core Show documentation
/*
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;
/**
* Allows creating customized argument matchers.
* This API was changed in Mockito 2.1.0 in an effort to decouple Mockito from Hamcrest
* and reduce the risk of version incompatibility.
* Migration guide is included close to the bottom of this javadoc.
*
* For non-trivial method arguments used in stubbing or verification, you have the following options
* (in no particular order):
*
* - refactor the code so that the interactions with collaborators are easier to test with mocks.
* Perhaps it is possible to pass a different argument to the method so that mocking is easier?
* If stuff is hard to test it usually indicates the design could be better, so do refactor for testability!
*
* - don't match the argument strictly, just use one of the lenient argument matchers like
* {@link Mockito#notNull()}. Some times it is better to have a simple test that works than
* a complicated test that seem to work.
*
* - implement equals() method in the objects that are used as arguments to mocks.
* Mockito naturally uses equals() for argument matching.
* Many times, this is option is clean and simple.
*
* - use {@link ArgumentCaptor} to capture the arguments and perform assertions on their state.
* Useful when you need to verify the arguments. Captor is not useful if you need argument matching for stubbing.
* Many times, this option leads to clean and readable tests with fine-grained validation of arguments.
*
* - use customized argument matchers by implementing {@link ArgumentMatcher} interface
* and passing the implementation to the {@link Mockito#argThat} method.
* This option is useful if custom matcher is needed for stubbing and can be reused a lot.
* Note that {@link Mockito#argThat} demonstrates NullPointerException auto-unboxing caveat.
*
* - use an instance of hamcrest matcher and pass it to
* {@link org.mockito.hamcrest.MockitoHamcrest#argThat(org.hamcrest.Matcher)}
* Useful if you already have a hamcrest matcher. Reuse and win!
* Note that {@link org.mockito.hamcrest.MockitoHamcrest#argThat(org.hamcrest.Matcher)} demonstrates NullPointerException auto-unboxing caveat.
*
* - Java 8 only - use a lambda in place of an {@link ArgumentMatcher} since {@link ArgumentMatcher}
* is effectively a functional interface. A lambda can be used with the {@link Mockito#argThat} method.
*
*
*
* Implementations of this interface can be used with {@link ArgumentMatchers#argThat} method.
* Use toString()
method for description of the matcher
* - it is printed in verification errors.
*
*
* class ListOfTwoElements implements ArgumentMatcher<List> {
* public boolean matches(List list) {
* return list.size() == 2;
* }
* public String toString() {
* //printed in verification errors
* return "[list of 2 elements]";
* }
* }
*
* List mock = mock(List.class);
*
* when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);
*
* mock.addAll(Arrays.asList("one", "two"));
*
* verify(mock).addAll(argThat(new ListOfTwoElements()));
*
*
* To keep it readable you can extract method, e.g:
*
*
* verify(mock).addAll(argThat(new ListOfTwoElements()));
* //becomes
* verify(mock).addAll(listOfTwoElements());
*
*
* In Java 8 you can treat ArgumentMatcher as a functional interface
* and use a lambda, e.g.:
*
*
* verify(mock).addAll(argThat(list -> list.size() == 2));
*
*
*
* Read more about other matchers in javadoc for {@link ArgumentMatchers} class.
*
2.1.0 migration guide
*
* All existing custom implementations of ArgumentMatcher
will no longer compile.
* All locations where hamcrest matchers are passed to argThat()
will no longer compile.
* There are 2 approaches to fix the problems:
*
* - a) Refactor the hamcrest matcher to Mockito matcher:
* Use "implements ArgumentMatcher" instead of "extends ArgumentMatcher".
* Then refactor
describeTo()
method into toString()
method.
*
* -
* b) Use
org.mockito.hamcrest.MockitoHamcrest.argThat()
instead of Mockito.argThat()
.
* Ensure that there is hamcrest dependency on classpath
* (Mockito does not depend on hamcrest any more).
*
*
*
* What option is right for you? If you don't mind having a compile-time dependency for Hamcrest,
* then the second option is probably right for you.
* Your choice should not have a big impact and is fully reversible -
* you can choose different option in future (and refactor the code)!
*
* @param type of argument
* @since 2.1.0
*/
@FunctionalInterface
public interface ArgumentMatcher {
/**
* Informs if this matcher accepts the given argument.
*
* The method should never assert if the argument doesn't match. It
* should only return false.
*
* See the example in the top level javadoc for {@link ArgumentMatcher}
*
* @param argument
* the argument
* @return true if this matcher accepts the given argument.
*/
boolean matches(T argument);
/**
* The type of the argument this matcher matches.
*
*
This method is used to differentiate between a matcher used to match a raw vararg array parameter
* from a matcher used to match a single value passed as a vararg parameter.
*
*
Where the matcher:
*
* - is at the parameter index of a vararg parameter
* - is the last matcher passed
* - this method returns a type assignable to the vararg parameter's raw type, i.e. its array type.
*
*
* ...then the matcher is matched against the raw vararg parameter, rather than the first element of the raw parameter.
*
* For example:
*
*
* // Given vararg method with signature:
* int someVarargMethod(String... args);
*
* // The following will match invocations with any number of parameters, i.e. any number of elements in the raw array.
* mock.someVarargMethod(isA(String[].class));
*
* // The following will match invocations with a single parameter, i.e. one string in the raw array.
* mock.someVarargMethod(isA(String.class));
*
* // The following will match invocations with two parameters, i.e. two strings in the raw array
* mock.someVarargMethod(isA(String.class), isA(String.class));
*
*
* Only matcher implementations that can conceptually match a raw vararg parameter should override this method.
*
* @return the type this matcher handles. The default value of {@link Void} means the type is not known.
* @since 4.11.0
*/
default Class> type() {
return Void.class;
}
}