Первая заглушка вызывается при добавлении дополнительной заглушки
У меня есть следующий объект, который я хочу проверить:
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;
}
}
Это мой тест:
@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);
}
}
}
Я перезаписываю anyString()
совпадение для конкретного аргумента. Я заглушаю download()
метод, так что он возвращает значение для конкретного аргумента и в противном случае выдает IOException, который обрабатывается MyObject.readFiles
,
Странная вещь здесь в том, что вторая заглушка (downloader.download("testFile")
) создает исключение IOException, установленное в первой заглушке (downloader.download(anyString())
). Я подтвердил это, бросив другое исключение в мою первую заглушку.
Может кто-нибудь объяснить мне, почему возникает исключение при добавлении дополнительной заглушки? Я думал, что создание заглушки не вызывает метод / другие заглушки.
3 ответа
Я думал, что создание заглушки не вызывает метод / другие заглушки.
Это предположение неверно, потому что заглушка вызывает ложные методы. Ваши методы тестирования все еще просты в Java!
С тех пор как anyString
перезапишет заглушку для любой конкретной строки, вам нужно будет написать два теста или заглушку для двух конкретных аргументов:
when(downloader.download("fail")).thenThrow(new IOException());
when(downloader.download("testFile")).thenReturn("mockContent");
Mockito - очень сложный кусок кода, который старается изо всех сил, чтобы вы могли писать
when(downloader.download(anyString())).thenThrow(new IOException());
что значит " when
downloader
с насмешкой download
метод вызывается с anyString
аргумент thenThrow
IOException
"(То есть его можно читать слева направо).
Однако, поскольку код по-прежнему простой Java, последовательность вызовов на самом деле:
String s1 = anyString(); // 1
String s2 = downloader.download(s1); // 2
when(s2).thenThrow(new IOException()); // 3
За кулисами, Мокито должен сделать это:
- зарегистрировать
ArgumentMatcher
для любого аргумента String - зарегистрировать вызов метода
download
наdownloader
макет, где аргумент определяется ранее зарегистрированнымArgumentMatcher
- зарегистрировать действие для ранее зарегистрированного вызова метода на макете
Если вы сейчас позвоните
... downloader.download("testFile") ...
downloader
макет проверяет, есть ли регистр действий для "testFile"
(есть, поскольку для любой строки уже есть действие) и, соответственно, IOException
,
Проблема в том, что когда ты пишешь
when(downloader.download("testFile")).thenReturn("mockContent");
первое, что нужно назвать downloader.download
, который вы уже оцепили, чтобы бросить исключение.
Решение состоит в том, чтобы использовать немного более универсальный синтаксис заглушки, который обеспечивает Mockito. Преимущество этого синтаксиса в том, что он не вызывает реальный метод при создании заглушки.
doThrow(IOException.class).when(downloader).download(anyString());
doReturn("mock content").when(downloader).download("test file");
Я перечислил другие преимущества этого второго синтаксиса в своем ответе здесь
Ваш второй ложный оператор переопределяется первым ложным оператором (потому что оба ложных оператора передают аргумент String). Если вы хотите рассказать о пробной версии, а также о пробном тесте, напишите 2 разных контрольных примера.