1. Обзор
В эти дни мы ожидаем позвонить в API REST в большинстве наших сервисов. Весна предоставляет несколько вариантов для создания клиента REST, и WebClient рекомендуется .
В этом быстром учебнике, мы будем смотреть на то, как службы единицы тестирования, WebClient для вызова API .
2. Мокинг
У нас есть два основных варианта для насмешек в наших тестах:
- Используйте Мокито имитировать поведение WebClient
- Используйте WebClient по-настоящему, но издеваться над услугой, которая она вызывает, используя MockWebСервер (окхттп) Я не против.
3. Использование Мокито
Mockito является наиболее распространенной библиотекой насмешек для Java. Это хорошо обеспечивает заранее определенные ответы на вызовы методов, но все становится сложным, когда насмешки свободно API. Это связано с тем, что в свободном API много объектов проходит между кодом вызова и макетом.
Например, давайте проявим Служба обслуживания класс с getEmployeeById метод получения данных через HTTP с помощью WebClient :
public class EmployeeService { public EmployeeService(String baseUrl) { this.webClient = WebClient.create(baseUrl); } public MonogetEmployeeById(Integer employeeId) { return webClient .get() .uri("http://localhost:8080/employee/{id}", employeeId) .retrieve() .bodyToMono(Employee.class); } }
Мы можем использовать Mockito, чтобы издеваться над этим:
@ExtendWith(MockitoExtension.class) public class EmployeeServiceTest { @Test void givenEmployeeId_whenGetEmployeeById_thenReturnEmployee() { Integer employeeId = 100; Employee mockEmployee = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER); when(webClientMock.get()) .thenReturn(requestHeadersUriSpecMock); when(requestHeadersUriMock.uri("/employee/{id}", employeeId)) .thenReturn(requestHeadersSpecMock); when(requestHeadersMock.retrieve()) .thenReturn(responseSpecMock); when(responseMock.bodyToMono(Employee.class)) .thenReturn(Mono.just(mockEmployee)); MonoemployeeMono = employeeService.getEmployeeById(employeeId); StepVerifier.create(employeeMono) .expectNextMatches(employee -> employee.getRole() .equals(Role.LEAD_ENGINEER)) .verifyComplete(); } }
Как мы видим, мы должны предоставить различные макет объекта для каждого вызова в цепи, с четырьмя различными когда / затемРетурн требуется вызов. Это многословный и громоздкий . Это также требует от нас знать детали реализации того, как именно наш сервис использует WebClient, что делает это хрупкий способ тестирования.
Как мы можем написать лучшие тесты для WebClient?
4. Использование MockWebServer
MockWebСервер , построенный командой Square, это небольшой веб-сервер, который может принимать и отвечать на запросы HTTP.
Взаимодействие с MockWebСервер из наших тестовых случаев позволяет нашему коду использовать реальные вызовы HTTP в местную конечную точку . Мы получаем преимущество тестирования предполагаемых взаимодействий HTTP и ни одна из проблем насмешливый сложный беглый клиент.
Использование MockWebСервер это рекомендовано Весенней командой для написания интеграционных тестов .
4.1. Зависимости MockWebServer
Использовать MockWebСервер , мы должны добавить Maven зависимостей для обеих okhttp и mockwebserver к нашему пом.xml:
com.squareup.okhttp3 okhttp 4.0.1 test com.squareup.okhttp3 mockwebserver 4.0.1 test
4.2. Добавление MockWebServer в наш тест
Давайте проверят наши Служба обслуживания с MockWebСервер :
public class EmployeeServiceMockWebServerTest { public static MockWebServer mockBackEnd; @BeforeAll static void setUp() throws IOException { mockBackEnd = new MockWebServer(); mockBackEnd.start(); } @AfterAll static void tearDown() throws IOException { mockBackEnd.shutdown(); } }
В вышеупомянутом тестовом классе JUnit setUp и tearDown метод заботится о создании и закрытии MockWebServer.
Следующим шагом является карта порта фактического вызова службы REST в MockWebServer’s портовые .
@BeforeEach void initialize() { String baseUrl = String.format("http://localhost:%s", mockBackEnd.getPort()); employeeService = new EmployeeService(baseUrl); }
Теперь пришло время создать заглушку так, чтобы MockWebСервер может ответить на HttpRequest .
4.3. Заглушая ответ
Давайте использовать MockWebServer’s удобный завеча метод очереди тестового ответа на веб-сервере:
@Test void getEmployeeById() throws Exception { Employee mockEmployee = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER); mockBackEnd.enqueue(new MockResponse() .setBody(objectMapper.writeValueAsString(mockEmployee)) .addHeader("Content-Type", "application/json")); MonoemployeeMono = employeeService.getEmployeeById(100); StepVerifier.create(employeeMono) .expectNextMatches(employee -> employee.getRole() .equals(Role.LEAD_ENGINEER)) .verifyComplete(); }
Когда фактический вызов API будет из getEmployeeById (сотрудник IntegerId) метод в нашем Служба обслуживания класс, MockWebСервер будет отвечать с очередью заглушки .
4.4. Проверка запроса
Мы также можем захотеть убедиться, что MockWebСервер был отправлен правильный HttpRequest .
MockWebСервер имеет удобный метод, названный takeRequest который возвращает экземпляр ЗаписьРеквест :
RecordedRequest recordedRequest = mockBackEnd.takeRequest(); assertEquals("GET", recordedRequest.getMethod()); assertEquals("/employee/100", recordedRequest.getPath());
С ЗаписьРеквест , мы можем проверить HttpRequest , который был получен, чтобы убедиться, что наши WebClient послал его правильно .
5. Заключение
В этом учебнике мы попробовали два основных варианта, доступных для макет WebClient на основе кода клиента REST .
Хотя Mockito работал и, возможно, хороший вариант для простых примеров, рекомендуемый подход заключается в использовании MockWebСервер .
Как всегда, исходный код для этой статьи доступен более чем на GitHub.