Как unit test логика обратного вызова?
Более полный вопрос заключается в том, что, учитывая зависимость, которая ожидает обратного вызова в качестве параметра, как написать unit test, который охватывает логику обратного вызова и все еще удается макетировать зависимость?
public class DoStuff {
public void runThis(Runnable callback) {
// call callback
}
}
public class ClassUnderTest {
private DoStuff stuffToDo;
public void methodUnderTest() {
this.stuffToDo.runThis(/*a runnable with some logic*/)
}
}
В приведенном выше примере я бы издевался над stuffToDo
, так как я должен проверять вызовы и выписывать выходы вызовов методов. Однако издевательская runThis
приводит к тому, что логика обратного вызова не тестируется. Кроме того, логика обратного вызова кажется, что она должна быть частной, поэтому я не ожидал бы ее проверить непосредственно; возможно, это неправильное представление с моей стороны.
Поскольку обратные вызовы используются довольно экстенсивно, я бы ожидал, что их будет распространенным методом для их тестирования, но я его не нашел.
Ответы
Ответ 1
Вы не можете выполнить ни одного теста. Если вы издеваетесь над чем-то, его издеваетесь, то есть он может только проверять аргументы и моделировать возвращаемые значения (которые вы настраиваете в тесте).
В самом деле, вся точка насмешки над чем-то заключается в том, чтобы проверить, что использует макет в изоляции. Если вы хотите unit test DoStuff
, вам не нужно беспокоиться об использовании какой-либо реализации обратного вызова, которая могла бы или не работать. Вы издеваетесь над обратным вызовом, чтобы не беспокоиться об этом.
У вас все еще есть хорошие тесты, проверяя код обратного вызова изолированно и проверяя изолированного пользователя обратного вызова (используя макет для обратного вызова) и, возможно, путем тщательного теста интеграции, где вы используете полностью настроенную компонент в целом.
Ответ 2
Здесь в основном вы хотите протестировать класс DoStuff. Это означает, что вам нужно проверить все методы внутри DoStuff, правильно?. Итак, в этом случае вам нужно сделать вместо того, чтобы издеваться над stuffToDo, вставить издеваемое Runnable в stuffToDo. И затем проверьте, был ли ваш runnable успешно выполнен или нет.
Но если у вас есть другие функции в классе, у вас может быть отдельный тест и издеваться над ними.
Ответ 3
В вашем конкретном случае это звучит так, как будто вы уже протестировали DoStuff
(или не волнуйтесь больше, так как это насмехается), и теперь специально тестируют отдельные теги Runnable
, которые вы разработали. В этом случае callback
звучит точно так, как вы хотите тестировать, таким же образом, кто-то может захотеть специально протестировать стратегию базы данных или стратегию в памяти напрямую.
Если это то, что вы пытаетесь, либо вы можете проверить его в черном ящике, используя его ClassUnderTest
, насколько это возможно. Или вы можете создать испытательный жгут на своем конкретном Runnable. Если вы освобождаете этот код и не хотите, чтобы ваш тестовый жгут был доступен, вы можете сделать частные методы проверки и поделиться своими данными специально с вашей сборкой unit test.
Посмотрите здесь для получения информации о том, как создавать сборки для друзей. Обычно я подписываю код unit test, поэтому мне не нужно гадать компилятор командной строки. Я полагаю, это зависит от вашей среды сборки.
Ответ 4
Если вы используете EasyMock, вы можете использовать andStubAnswer
для вызова runnable.
doSomethingMock.runThis(runnable);
expectLastCall().andStubAnswer(new IAnserable<Void>() {
Runnable runnable = (Runnable)getCurrentArguments()[0];
runnable.run();
return null;
});
Я полагаю, что другие насмешливые рамки содержат нечто похожее.
Ответ 5
Как насчет поддельного DoStuff, который безоговорочно запускает Runnable?
Затем вы просто ощущаете эффекты - изменения, которые следует соблюдать, если ваш обратный вызов был выполнен.