'Mockito: how to stub void methods to run some code when called
I want to stub a repository class to test another class (Holder class) that has a repository. The repository interface supports CRUD operations, and has many methods, but my unit test on the Holder class only needs to call two of them. The repository interface:
public interface IRepo {
public void remove(String... sarr);
public void add(String... sarr);
//Lots of other methods I don't need now
}
I want to create a repository mock that can store instances, define logic for add and remove only, and also provide a means of checking what is stored on it after calling add and remove.
If I do:
IRepo repoMock = mock(IRepo.class);
Then I have a dumb object that does nothing on each method. That's OK, now I just need to define behaviour for add and remove.
I could create a Set<String> and stub only those two methods to work on the set. Then I'd instantiate a Holder that has an IRepo, inject the partially stubbed mock, and after exercising the holder, check the set to verify it contains what it should.
I've managed to partially stub a void method like remove using the deprecated method stubVoid:
Set<String> mySet = new HashSet<>();
stubVoid(repoMock).toAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
return null;
}
}).on().remove(Matchers.<String>anyVararg());
But is deprecated, and it is not much better than creating a partial implementation for IRepo. Is there a better way?
NOTE: Java 7 answers only please, this should run in Android.
Solution 1:[1]
You can use
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
//DO SOMETHING
return null;
}
}).when(...).remove(Matchers.<String>anyVararg());
From the Javadoc:
Use doAnswer() when you want to stub a void method with generic Answer.
Stubbing voids requires different approach from Mockito.when(Object) because the compiler does not like void methods inside brackets...
Example:
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Mock mock = invocation.getMock();
return null;
}}).when(mock).someMethod();
See examples in javadoc for Mockito
Solution 2:[2]
Suppose you have
public class IFace {
public void yourMethod() {
}
}
Then to mock it you need
IFace mock = Mockito.mock(IFace.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
//PUT YOUR CODE HERE
return null;
}
}).when(mock).yourMethod();
Solution 3:[3]
If you really don't like to return null in your implementation of Answer, you can create your own Answer implementation that delegates to a void method:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation);
return null;
}
protected abstract void doSomething(InvocationOnMock invocation);
}
Then your test has one line less:
Set<String> mySet = new HashSet<>();
Mockito.doAnswer(new DoesSomethingAnswer() {
@Override
protected void doSomething(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
}
}).when(repoMock).remove(Matchers.<String> anyVararg());
Or, if you just need the arguments from the invocation:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation.getArguments());
return null;
}
protected abstract void doSomething(Object[] args);
}
Solution 4:[4]
In addition to https://stackoverflow.com/a/32139397/4471199 you can use lambda:
Mockito.doAnswer(
invocation -> {
// DO SOMETHING
return null;
}
).when(repoMock).remove(Matchers.<String>anyVararg());
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Saminda Peramuna |
| Solution 2 | |
| Solution 3 | Ruben |
| Solution 4 |
