I have the following object which I want to test:
public class MyObject {
@Inject
Downloader downloader;
public List<String> readFiles(String[] fileNames) {
List<String> files = new LinkedList<>();
for (String fileName : fileNames) {
try {
files.add(downloader.download(fileName));
} catch (IOException e) {
files.add("NA");
}
}
return files;
}
}
This is my test:
@UseModules(mockTest.MyTestModule.class)
@RunWith(JukitoRunner.class)
public class mockTest {
@Inject Downloader downloader;
@Inject MyObject myObject;
private final String[] FILE_NAMES = new String[] {"fail", "fail", "testFile"};
private final List<String> EXPECTED_FILES = Arrays.asList("NA", "NA", "mockContent");
@Test
public void testException() throws IOException {
when(downloader.download(anyString()))
.thenThrow(new IOException());
when(downloader.download("testFile"))
.thenReturn("mockContent");
assertThat(myObject.readFiles(FILE_NAMES))
.isEqualTo(EXPECTED_FILES);
}
public static final class MyTestModule extends TestModule {
@Override
protected void configureTest() {
bindMock(Downloader.class).in(TestSingleton.class);
}
}
}
I am overwriting the anyString() matcher for a specific argument. I am stubbing the download() method so that it returns a value for a specific argument and otherwise throws an IOException which gets handled by MyObject.readFiles.
The weird thing here is that the second stub (downloader.download("testFile")) throws the IOException set in the first stub (downloader.download(anyString())). I have validated that by throwing a different exception in my first stub.
Can someone explain me why the exception is thrown when adding an additional stub? I thought that creating a stub does not call the method/other stubs.
This assumption is wrong, because stubbing is calling the mocks methods. Your test methods are still plain java!
Since stubbing for
anyStringwill overwrite stubbing for any specific string you will either have to write two tests or stub for two specific arguments:Mockito is a very sophisticated piece of code that tries its best so that you can write
which means “
whenthedownloaders mockdownloadmethod is called withanyStringargumentthenThrowanIOException” (i.e. it can be read from left to right).However, since the code is still plain java, the call sequence actually is:
Behind the scenes, Mockito needs to do this:
ArgumentMatcherfor any String argumentdownloadon thedownloadermock where the argument is defined by the previously registeredArgumentMatcherIf you now call
the
downloadermock checks whether there is an action register for"testFile"(there is, since there is already an action for any String) and accordingly throws theIOException.