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 .