Весёлый шаблон для отдыха

Дразнить шаблон отдыха весной

1. Вступление

Часто мы сталкиваемся с приложениями, которые выполняют какие-то веб-запросы. Когда дело доходит до тестирования этого поведения, у нас есть несколькоoptionsс приложениями Spring.

In this quick tutorial, we’ll look at just a couple of ways of mocking such calls performed only through a RestTemplate.

Мы начнем тестирование с Mockito, популярной библиотеки имитаторов. Затем мы воспользуемся Spring Test, который предоставляет нам механизм для создания фиктивного сервера для определения взаимодействия с сервером.

2. ИспользуяMockito

Мы могли бы использовать Mockito, чтобы вместе издеваться надRestTemplate al. При таком подходе тестирование нашего сервиса будет таким же простым, как и любой другойtest involving mocking.

Предположим, у нас есть простой классEmployeeService, который получает данные о сотрудниках через HTTP:

@Service
public class EmployeeService {

    @Autowired
    private RestTemplate restTemplate;

    public Employee getEmployee(String id) {
    ResponseEntity resp =
          restTemplate.getForEntity("http://localhost:8080/employee/" + id, Employee.class);

    return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null;
    }
}

Давайте реализуем наш тест для предыдущего кода: __

@RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceTest {

    @Mock
    private RestTemplate restTemplate;

    @InjectMocks
    private EmployeeService empService = new EmployeeService();

    @Test
    public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
        Employee emp = new Employee(“E001”, "Eric Simmons");
        Mockito
          .when(restTemplate.getForEntity(
            “http://localhost:8080/employee/E001”, Employee.class))
          .thenReturn(new ResponseEntity(emp, HttpStatus.OK));

        Employee employee = empService.getEmployee(id);
        Assert.assertEquals(emp, employee);
    }
}

В приведенном выше тестовом классе JUnit мы сначала попросили Mockito создать фиктивный экземплярRestTemplate, используя аннотацию@Mock.

Затем мы аннотировали экземплярEmployeeService с помощью@InjectMocks, чтобы вставить в него фиктивный экземпляр.

Наконец, в методе тестирования мы определили поведение нашего макета с помощьюMockito’s when/then support.

3. Использование Spring Test

Модуль Spring Test включает фиктивный сервер с именемMockRestServiceServer.With this approach, we configure the server to return a particular object when a specific request is dispatched through our RestTemplate instance.. Наконец, мы можемverify() на этом экземпляре сервера независимо от того, оправдались ли все ожидания или нет.

MockRestServiceServer фактически работает, перехватывая вызовы HTTP API с помощьюMockClientHttpRequestFactory. На основе нашей конфигурации он создает список ожидаемых запросов и соответствующих ответов. Когда экземплярRestTemplate вызывает API, он ищет запрос в своем списке ожиданий и возвращает соответствующий ответ.

Таким образом, устраняется необходимость запускать HTTP-сервер на любом другом порту для отправки фиктивных ответов.

Давайте создадим простой тест для того же примераgetEmployee(), используяMockRestServiceServer:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringTestConfig.class)
public class EmployeeServiceMockRestServiceServerUnitTest {

    @Autowired
    private EmployeeService empService;
    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;
    private ObjectMapper mapper = new ObjectMapper();

    @Before
    public void init() {
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }

    @Test
    public void givenMockingIsDoneByMockRestServiceServer_whenGetIsCalled_thenReturnsMockedObject()() {
        Employee emp = new Employee("E001", "Eric Simmons");
        mockServer.expect(ExpectedCount.once(),
          requestTo(new URI("http://localhost:8080/employee/E001")))
          .andExpect(method(HttpMethod.GET))
          .andRespond(withStatus(HttpStatus.OK)
          .contentType(MediaType.APPLICATION_JSON)
          .body(mapper.writeValueAsString(emp))
        );

        Employee employee = empService.getEmployee(id);
        mockServer.verify();
        Assert.assertEquals(emp, employee);
    }
}

В предыдущем фрагменте мы использовали статические методы изMockRestRequestMatchers иMockRestResponseCreators для определения ожидания и ответа на вызов REST в ясной и удобочитаемой форме:

import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;

Мы должны помнить, чтоRestTemplate в тестовом классе должен быть тем же экземпляром, что и в классеEmployeeService. Чтобы убедиться в этом, мы определили bean-компонент RestTemplate в конфигурации Spring и автоматически подключили экземпляр в тесте и реализации:

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

ИспользованиеMockRestServiceServer очень полезно, когда мы пишем наши интеграционные тесты, и нам нужно только имитировать внешние HTTP-вызовы.

4. Заключение

В этой краткой статье мы обсудили несколько эффективных вариантов создания внешних вызовов API REST через HTTP при написании модульных тестов.

Исходный код этой статьи доступенover on GitHub.