/
ArgumentMatcher.java
169 lines (166 loc) · 7.26 KB
/
ArgumentMatcher.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* 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.
* <p>
* For non-trivial method arguments used in stubbing or verification, you have following options
* (in no particular order):
* <ul>
* <li>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!
* </li>
* <li>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.
* </li>
* <li>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.
* </li>
* <li>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.
* </li>
* <li>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 <b>NullPointerException</b> auto-unboxing caveat.
* </li>
* <li>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 <b>NullPointerException</b> auto-unboxing caveat.
* </li>
* <li>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.</li>
* </ul>
*
* <p>
* Implementations of this interface can be used with {@link ArgumentMatchers#argThat} method.
* Use <code>toString()</code> method for description of the matcher
* - it is printed in verification errors.
*
* <pre class="code"><code class="java">
* 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()));
* </code></pre>
*
* To keep it readable you can extract method, e.g:
*
* <pre class="code"><code class="java">
* verify(mock).addAll(<b>argThat(new ListOfTwoElements())</b>);
* //becomes
* verify(mock).addAll(<b>listOfTwoElements()</b>);
* </code></pre>
*
* In Java 8 you can treat ArgumentMatcher as a functional interface
* and use a lambda, e.g.:
*
* <pre class="code"><code class="java">
* verify(mock).addAll(<b>argThat(list -> list.size() == 2)</b>);
* </code></pre>
*
* <p>
* Read more about other matchers in javadoc for {@link ArgumentMatchers} class.
* <h2>2.1.0 migration guide</h2>
*
* All existing custom implementations of <code>ArgumentMatcher</code> will no longer compile.
* All locations where hamcrest matchers are passed to <code>argThat()</code> will no longer compile.
* There are 2 approaches to fix the problems:
* <ul>
* <li>a) Refactor the hamcrest matcher to Mockito matcher:
* Use "implements ArgumentMatcher" instead of "extends ArgumentMatcher".
* Then refactor <code>describeTo()</code> method into <code>toString()</code> method.
* </li>
* <li>
* b) Use <code>org.mockito.hamcrest.MockitoHamcrest.argThat()</code> instead of <code>Mockito.argThat()</code>.
* Ensure that there is <a href="http://hamcrest.org/JavaHamcrest/">hamcrest</a> dependency on classpath
* (Mockito does not depend on hamcrest any more).
*
* </li>
* </ul>
* What option is right for you? If you don't mind compile dependency to hamcrest
* then option b) is probably right for you.
* Your choice should not have big impact and is fully reversible -
* you can choose different option in future (and refactor the code)
*
* @param <T> type of argument
* @since 2.1.0
*/
@FunctionalInterface
public interface ArgumentMatcher<T> {
/**
* Informs if this matcher accepts the given argument.
* <p>
* The method should <b>never</b> assert if the argument doesn't match. It
* should only return false.
* <p>
* 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.
*
* <p>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.
*
* <p>Where the matcher:
* <ul>
* <li>is at the parameter index of a vararg parameter</li>
* <li>is the last matcher passed</li>
* <li>this method returns a type assignable to the vararg parameter's raw type, i.e. its array type.</li>
* </ul>
*
* ...then the matcher is matched against the raw vararg parameter, rather than the first element of the raw parameter.
*
* <p>For example:
*
* <pre class="code"><code class="java">
* // 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));
* </code></pre>
*
* <p>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 5.0.0
*/
default Class<?> type() {
return Void.class;
}
}