«1. Обзор
В этом коротком руководстве мы сосредоточимся на том, как тестировать обратные вызовы с помощью популярной среды тестирования Mockito.
Мы рассмотрим два решения, сначала используя ArgumentCaptor, а затем интуитивно понятный метод doAnswer().
Чтобы узнать больше о тестировании с помощью Mockito, ознакомьтесь с нашей серией статей о Mockito здесь.
2. Введение в обратные вызовы
Обратный вызов — это фрагмент кода, который передается в качестве аргумента методу, который, как ожидается, вызовет (выполнит) аргумент в заданное время.
Это выполнение может быть немедленным, как при синхронном обратном вызове, но чаще это может произойти позже, как при асинхронном обратном вызове.
Обычный сценарий использования обратных вызовов — во время взаимодействия службы, когда нам нужно обработать ответ от вызова службы.
В этом руководстве мы будем использовать интерфейс службы, показанный ниже, в качестве соавтора в тестовых примерах:
public interface Service {
void doAction(String request, Callback<Response> callback);
}
В аргументе обратного вызова мы передаем класс, который будет обрабатывать ответ, используя ответ (T ответ) метод:
public interface Callback<T> {
void reply(T response);
}
2.1. Простой сервис
Мы также воспользуемся простым примером сервиса, чтобы продемонстрировать, как передать и вызвать обратный вызов:
public void doAction() {
service.doAction("our-request", new Callback<Response>() {
@Override
public void reply(Response response) {
handleResponse(response);
}
});
}
Метод handleResponse проверяет, является ли ответ допустимым, прежде чем добавлять некоторые данные в объект Response. :
private void handleResponse(Response response) {
if (response.isValid()) {
response.setData(new Data("Successful data response"));
}
}
Для ясности мы решили не использовать выражение Java Lamda, но вызов service.doAction также можно было бы написать более лаконично:
service.doAction("our-request", response -> handleResponse(response));
Чтобы узнать больше о выражениях Lambda, посмотрите здесь .
3. Использование ArgumentCaptor
Теперь давайте посмотрим, как мы используем Mockito для захвата объекта обратного вызова с помощью ArgumentCaptor:
@Test
public void givenServiceWithValidResponse_whenCallbackReceived_thenProcessed() {
ActionHandler handler = new ActionHandler(service);
handler.doAction();
verify(service).doAction(anyString(), callbackCaptor.capture());
Callback<Response> callback = callbackCaptor.getValue();
Response response = new Response();
callback.reply(response);
String expectedMessage = "Successful data response";
Data data = response.getData();
assertEquals(
"Should receive a successful message: ",
expectedMessage, data.getMessage());
}
В этом примере мы сначала создаем ActionHandler перед вызовом doAction метод этого обработчика. Это просто оболочка для нашего вызова метода doAction Simple Service, в котором мы вызываем наш обратный вызов.
Затем мы проверяем, что doAction был вызван для нашего фиктивного экземпляра службы, передавая anyString() в качестве первого аргумента и callbackCaptor.capture() в качестве второго, и именно здесь мы захватываем объект обратного вызова. Затем можно использовать метод getValue() для возврата захваченного значения аргумента.
Теперь, когда у нас есть объект обратного вызова, мы создаем объект Response, который является допустимым по умолчанию, прежде чем мы вызовем метод ответа напрямую и утверждаем, что данные ответа имеют правильное значение.
4. Использование метода doAnswer()
Теперь мы рассмотрим распространенное решение для заглушек методов, которые имеют обратные вызовы, используя объект Mockito Answer и метод doAnswer для заглушки метода void doAction:
@Test
public void givenServiceWithInvalidResponse_whenCallbackReceived_thenNotProcessed() {
Response response = new Response();
response.setIsValid(false);
doAnswer((Answer<Void>) invocation -> {
Callback<Response> callback = invocation.getArgument(1);
callback.reply(response);
Data data = response.getData();
assertNull("No data in invalid response: ", data);
return null;
}).when(service)
.doAction(anyString(), any(Callback.class));
ActionHandler handler = new ActionHandler(service);
handler.doAction();
}
И , во втором примере мы сначала создаем недопустимый объект Response, который будет использоваться позже в тесте.
Затем мы настраиваем ответ в нашей фиктивной службе, чтобы при вызове doAction мы перехватывали вызов и получали аргументы метода, используя invocation.getArgument(1), чтобы получить аргумент обратного вызова.
Последним шагом является создание ActionHandler и вызов doAction, который вызывает вызов ответа.
Чтобы узнать больше о методах заглушки void, загляните сюда.
3. Заключение
В этой краткой статье мы рассмотрели два разных подхода к тестированию обратных вызовов при тестировании с помощью Mockito.
Как всегда, примеры доступны в этом проекте GitHub.