Перейти к основному содержимому

Тестирование обратных вызовов с Mockito

· 4 мин. чтения

1. Обзор

В этом коротком руководстве мы сосредоточимся на том, как тестировать обратные вызовы с помощью популярной среды тестирования Mockito .

Мы рассмотрим два решения, сначала используя ArgumentCaptor , а затем интуитивно понятный метод doAnswer() .

Чтобы узнать больше о хорошем тестировании с помощью Mockito, ознакомьтесь с нашей серией статей о Mockito здесь .

2. Введение в обратные вызовы

Обратный вызов — это фрагмент кода, который передается в качестве аргумента методу, который, как ожидается, вызовет (выполнит) аргумент в заданное время .

Это выполнение может быть немедленным, как при синхронном обратном вызове, но чаще это может происходить позднее, как при асинхронном обратном вызове.

Обычный сценарий использования обратных вызовов — во время взаимодействия со службой, когда нам нужно обработать ответ от вызова службы .

В этом руководстве мы будем использовать интерфейс службы , показанный ниже, в качестве соавтора в тестовых примерах:

public interface Service {
void doAction(String request, Callback<Response> callback);
}

В аргументе Callback мы передаем класс, который будет обрабатывать ответ, используя метод answer(T response) :

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));

Чтобы узнать больше о лямбда-выражениях, загляните сюда .

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 .