Mockito Programming Model: Difference between revisions
Line 265: | Line 265: | ||
verifyNoMoreInteractions(mock); | verifyNoMoreInteractions(mock); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==Verifying Invocation Order== | |||
<font color=darkgray>TODO Mockito Essentials "Verifying an invocation order".</font> | |||
==Verifying Arguments with <tt>ArgumentCaptor</tt>== | ==Verifying Arguments with <tt>ArgumentCaptor</tt>== | ||
<font color=darkgray>TODO Mockito Essentials "Verifying arguments using ArgumentCaptor"</font> | <font color=darkgray>TODO Mockito Essentials "Verifying arguments using ArgumentCaptor". | ||
Generic collection arguments. | |||
Variable arguments and arrays. | |||
</font> | |||
=Resetting Mock Objects= | =Resetting Mock Objects= | ||
A mock object can be reset via API. | A mock object can be reset via API. |
Revision as of 00:25, 21 July 2021
Internal
Overview
Mockito provides a fluent API to mock Java objects.
API
import static org.mockito.Mockito.mock;
import com.example.ExternalDependency;
public class SomeClassTest {
private ExternalDependency mockExternalDependency;
@Before
public void setUp() {
mockExternalDependency = mock(ExternalDependency.class);
}
@Test
public void someTest() throws Exception {
...
}
}
Annotations
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.example.ExternalDependency;
import static org.mockito.Mockito.when;
public class SomeClassTest {
private AutoCloseable mocks;
@Mock
private ExternalDependency mockExternalDependency;
@Before
public void openMocks() {
mocks = MockitoAnnotations.openMocks(this);
}
@After
public void releaseMocks() throws Exception {
mocks.close();
}
@Test
public void someTest() throws Exception {
when(mockExternalDependency.someMethod()).thenReturn(...);
...
}
}
Implementing Stubs
A stub returns synthetic responses or throws exceptions when its methods are invoked. Mockito supports stubbing and by returning a given value when a specific method of the managed test double is called. Mockito implements the stub functionality with Mockito.when(<method>).then*(...)
pattern - using this API pattern is often referred to as "setting the expectations". The synthetic response is selected based on the arguments of the call, using the arguments values themselves or argument matchers:
public class ExternalDependency {
public String someMethod() {
...
}
}
import static org.mockito.Mockito.when;
public class SomeClassTest {
@Mock
private ExternalDependency mockExternalDependency;
@Test
public void someTest() throws Exception {
when(mockExternalDependency.someMethod()).thenReturn("some synthetic result");
...
}
}
The when()
configures the method(s) to stub, or the trigger action. The then*()
methods specify what to do when the trigger is activated. Void methods are a special case.
Void Methods
Unit testing void methods is difficult. Conventionally, a unit test provides arguments to a method and checks the result, working with the direct output of the method. For void methods, the method presumably changes the internal state of the objects under test, to the unit test must make assertions on the indirect output of the method. A common pattern to implement this is to provide managed mocks so the void methods acts on those instead of real dependencies.
By default, the managed test double does nothing on void methods, so there's no need to configure anything on it. The invocation on a void method will just complete successfully. Whether the invocation was performed or not can be checked with verify()
.
doAnswer() - Executing Arbitrary Logic for Void Methods
If we need to execute arbitrary logic when a void method is invoked, use this pattern:
doAnswer(answer).when(mockObject).<void-method-name>(arguments);
doAnswer(new Answer() { ... }).when(mockExternalDependency).writeLine("....");
For more details about Answer objects, see Answer below.
If we need to simulate an exception that is thrown by a void method, use this pattern:
toThrow() - Throwing Exceptions for Void Methods
doThrow(exception).when(mockObject).<void-method-name>(arguments);
doThrow(IOException.class).when(mockExternalDependency).writeLine("....");
doNothing()
Stub Responses for Non-Void Methods
The common pattern on non-void methods is:
when(mockExternalDependency.<some-method>(...)).then*(...);
thenReturn()
thenReturn(...)
returns the given value. It has several variants:
thenReturn(value)
: return the same value every time.thenReturn(value1, value2, value3, ...)
: return the first value on first invocation, second value on the second invocation, etc. The equivalent is:thenReturn(value1).thenReturn(value2).thenReturn(value3). ...
thenThrow()
thenThrow(Throwable)
throws the given exception. This can be used together with JUnit feature that provides syntactic support for tests that are supposed to check exceptions (@Test(expected = <exception-class>)
).
when(mockExternalDependency.someMethod()).thenThrow(IOException.class);
There is alternative syntax for throwing exceptions on void methods.
thenCallRealMethod()
thenCallRealMethod()
delegates the invocation to the real external dependency.
thenAnswer()
thenAnswer(Answer answer)
executes custom logic and compute a value to return. This turns the stub object into a fake. It uses Answers:
Answer
Answer
implementation is a callback. This is considered a somewhat controversial feature, as increases the complexity of the code. thenReturn()
and thenThrow()
should be used instead, if possible.
when(mock.someMethod(...)).thenAnswer(new Answer() {
public Object answer(InvocationOnMock i) {
Object[] args = i.getArguments();
Object mock = i.getMock();
return "called with arguments: " + Arrays.toString(args);
}
});
when(mock.someMethod(...)).then(new Answer() { ... });
Also see executing arbitrary logic when void methods are invoked, above.
Argument Matchers
The test double can be configured prior to running the test and programmed how to react when a method is invoked with specific arguments by using the Mockito.when(...)
API. This is achieved using a mechanism called argument matchers. Argument matchers are used to simulate different responses, either specific return values or exceptions, from a method, depending on the values of the arguments.
The default behavior in absence of any configured argument matcher is that the method returns the default value for the return type: 0 for int
, null
for String
, etc.
The test double can be configured to issue specific responses to a method invocation based on individual argument values, predefined wildcard matchers or custom matchers. When using matchers, all arguments of a method must be provided by matchers. Mixing individual argument values and wildcard matchers is not allowed. The following invocation will fail:
verify(mock).someMethod(1, anyString(), "some string");
However, this situation can be easily worked around by using the eq(...)
in lieu of an individual value:
verify(mock).someMethod(eq(1), anyString(), eq("some string"));
Individual Argument Values
Wildcard Matchers
Mockito wildcard marchers are static methods of the org.mockito.ArgumentMatchers class.
Matcher | Notes |
---|---|
any() | |
anyObject() | |
any(Class<T> c) | |
isA(Class<T> c) | Example below |
anyVararg() | |
anyBoolean() anyByte() anyChar() anyInt() anyLong() anyFloat() anyDouble() anyShort() anyString() | |
anyList() anyListOf(Class<T> c) | |
anySet() anySetOf(Class<T> c) | |
anyMap() anyMapOf(Class<K> keyC, Class<V> valueC) | |
anyCollection() anyCollectionOf(Class<T> c) | |
anyIterable() anyIterableOf(Class<T> c) | |
eq(T value)
eq(boolean value) eq(byte value) eq(char value) | |
refEq(T value, String... excludeFields) | |
same(T value) | |
isNull() isNull(Class<T> c) notNull() notNull(Class<T> c) isNotNull() isNotNull(Class<T> c) | |
nullable(Class<T> c) | |
contains(String substring) | |
matches(String regex) matches(String regex) | |
endsWith(String suffix) startsWith(String prefix) | |
argThat(ArgumentMatcher<T> m) charThat(ArgumentMatcher<Character> m) booleanThat(ArgumentMatcher<Boolean> m) byteThat(ArgumentMatcher<Byte> m) shortThat(ArgumentMatcher<Short> m) intThat(ArgumentMatcher<Integer> m) longThat(ArgumentMatcher<Long> m) floatThat(ArgumentMatcher<Float> m) doubleThat(ArgumentMatcher<Double> m) |
isA()
public class ExternalDependency {
public String someMethodWithArg(String s) {
...
}
}
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.when;
...
when(mockExternalDependency.someMethodWithArg(isA(String.class))).thenReturn(...);
Why is isA() needed, why not provide the class, directly?
Custom ArgumentMatcher
TODO. "Working with a custom ArgumentMatcher class" section in Mockito Essentials.
Implementing Spies
Testing Interaction with the Test Double
Number of Invocations
Many times during testing it is useful to know if our mocked external dependency was called into with a specific method, or any method, how many times per method, and so on. Mockito exposes API for this in form of the Mockito.verify(...)
set of methods. The mock object should be declared and configured as described in the Annotations section. Then the number of invocations of certain methods, or whether the methods have been invoked at all, can be tested with:
import static org.mockito.Mockito.verify;
...
verify(mock).someMethod("some argument");
This invocation succeeds if the method someMethod()
was invoked with the argument "some argument"
once and only once. The invocation is equivalent with:
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
...
verify(mock, times(1)).someMethod("some argument");
Other options:
verify(mock, never()).someMethod("some argument");
verify(mock, atMostOnce()).someMethod("some argument");
verify(mock, atLeastOnce()).someMethod("some argument");
verify(mock, atLeast(2)).someMethod("some argument");
verify(mock, atMost(5)).someMethod("some argument");
verify(mock, only()).someMethod("some argument");
Mock-wide Interactions
verifyZeroInteractions(mockOne, mockTwo);
verifyNoMoreInteractions(mock);
Verifying Invocation Order
TODO Mockito Essentials "Verifying an invocation order".
Verifying Arguments with ArgumentCaptor
TODO Mockito Essentials "Verifying arguments using ArgumentCaptor".
Generic collection arguments.
Variable arguments and arrays.
Resetting Mock Objects
A mock object can be reset via API.