Рубрики
Без рубрики

Spring Boot – Стратегии для тестирования Rest API

Spring Boot – Стратегии для тестирования Rest API Для осуществления тестирования приложения… С тегом spring, java, тестирование, новички.

Для осуществления тестирования приложения Spring Boot REST API, у нас есть два метода:

  • Внутрисерверный тест:
    • Автономный режим: пользователь MockMvc sem contexto
    • Весенний контекст: usar MockMvc Весна геренсиадо пело
  • Тестирование вне сервера
    • Spring Boot Test com макет: usar MockMvc
    • Интеграционный тест: пользователь RestTemplate ou TestRestTemplate

Независимо от конфигурации, тестирование, написание будет похож, от всего в форме отправки тела запроса, где мы можем написать чистого JSON или сериализации объекта.

Внутрисерверный тест

Автономный режим MockMvc com

Мы можем запустить тест в автономном режиме, где contxto Spring не загружается. В нем mockamos зависимости от контроллера и instânciamos других bean-компонентов, требуемых вручную.

  • JUnit 4: использование бегуна MockitoJUnitRunner
  • JUnit 5: использует расширение MockitoExtension

Расширение Mockito Usamos a classe Mockito Extension, мы Используем класс MockMvcBuilders

@ExtendWith(MockitoExtension.class)
public class PetsControllerMockMvcStandaloneTest {
    private MockMvc mvc;

    @Mock
    private PetsRepository petsRepository;

    @InjectMocks
    private PetsController petsController;

    private JacksonTester json;

    @BeforeEach
    public void setup() {
        // se estiver usando JUnit 4
        // MockitoAnnotations.initMocks(this);

        // não podemos usar @AutoConfigureJsonTesters (já que não existe o contexto do Spring - então inicializamos na mão)
        JacksonTester.initFields(this, new ObjectMapper());

        MockMvcBuilders.standaloneSetup(petsController)
                .setControllerAdvice(new PetExceptionHandler())
                .addFilters(new ApiVersionFilter())
                .build();
    }

    @Test
    public void should_return_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willReturn(Optional.of(new Pet(42, "Marley", "Wesley")));

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getContentAsString())
            .isEqualTo(
                json.write(new Pet(42, "Marley", "Wesley")).getJson()
            );
    }

    @Test
    public void should_return_not_found_for_non_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willThrow(new PetNotFoundException());

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
        assertThat(response.getContentAsString()).isEmpty();
    }

    @Test
    public void should_create_new_pet() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    post("/pets")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(
                            json.write(new Pet("Marley", "Wesley")).getJson()
                        )
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());

        ArgumentCaptor argCaptor = ArgumentCaptor.forClass(Pet.class);
        verify(petsRepository).save(argCaptor.capture());
        Pet pet = argCaptor.getValue();

        assertThat(pet.getId()).isEqualTo(0);
        assertThat(pet.getName()).isEqualTo("Marley");
        assertThat(pet.getOwner()).isEqualTo("Wesley");
    }

    @Test
    public void should_add_api_version_header() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getHeaders("X-PETS-VERSION")).containsOnly("v1");
    }
}

Расширение Mockito Samos a classe || MockMvcBuilders || para criar o contexto para teste fornecendo todas as peças necessárias: MockMvc com Spring Context

Расширение Mockito Samos a classe || MockMvcBuilders || para crear o context para teste fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o teste inicializando o contexto do Spring. Расширение Mockito Samos a classe || MockMvcBuilders || para crear o context para test fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o test iniciaO runner provido pelo Spring irá carregar todo contexto necessário para o controlle (макеты, фильтры, советы и т.д.). лизандо о том, как сделать весну. Mockito Extension Самос класс || MockMvcBuilders||, чтобы создавать контекст для теста, обеспечивая все необходимые детали: MockMVC с Spring Context Можем запустить тест iniciaO runner, предоставленный Spring будет загружать весь контекст, необходимый для controlEsse формате считаться Integration Test, потому что другие элементы Spring и приложения (filters, advices) добавляются автоматически. и (мокс, filters, advices, etc). lizando контекст Spring.

Mockito Extension Самос класс MockMvcBuilders , чтобы создавать контекст для теста, обеспечивая все необходимые детали: MockMVC с Spring Context Можем запустить тест iniciaO runner, предоставленный Spring будет загружать весь контекст, необходимый для controlEsse формате считаться Integration Test, потому что другие элементы Spring и приложения (filters, adviceNota: в Spring Boot 2.1+, заметки @... s) добавляются автоматически. и (мокс, filters, advices, etc). lizando контекст Spring. Mockito Extension Samos a classe

@AutoConfigureJsonTesters
@WebMvcTest(PetsController.class)
public class PetsControllerMockMvcWithContextTest {
    @Autowired
    private MockMvc mvc;

    @MockBean
    private PetsRepository petsRepository;

    // inicializado automaticamente pelo @AutoConfigureJsonTesters
    @Autowired
    private JacksonTester json;

    @Test
    public void should_return_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willReturn(Optional.of(new Pet(42, "Marley", "Wesley")));

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getContentAsString())
            .isEqualTo(
                json.write(new Pet(42, "Marley", "Wesley")).getJson()
            );
    }

    @Test
    public void should_return_not_found_for_non_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willThrow(new PetNotFoundException());

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
        assertThat(response.getContentAsString()).isEmpty();
    }

    @Test
    public void should_create_new_pet() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    post("/pets")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(
                            json.write(new Pet("Marley", "Wesley")).getJson()
                        )
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());

        ArgumentCaptor argCaptor = ArgumentCaptor.forClass(Pet.class);
        verify(petsRepository).save(argCaptor.capture());
        Pet pet = argCaptor.getValue();

        assertThat(pet.getId()).isEqualTo(0);
        assertThat(pet.getName()).isEqualTo("Marley");
        assertThat(pet.getOwner()).isEqualTo("Wesley");
    }

    @Test
    public void should_add_api_version_header() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getHeaders("X-PETS-VERSION")).containsOnly("v1");
    }
}

Mockito Extension Samos a classe || MockMvcBuilders || para crear o context param test fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o test iniciaO runner provido pelo Spring ira carregar todo contexto necessário para o controlEsse formato é mais considerado Интеграционный тест porque outros elementos do Spring e da aplicação (фильтры, adviceTests || do Spring já são decorados com || @ExtendWith(SpOutside-Серверный тест ringExtension.class ) Примечание: нет пружинной загрузки 2.1+, как указано || @… s) são adicionados automaticamente. e (насмешки, фильтры, советы и т.д.). лизандо о том, как сделать весну.

Mockito Extension Samos a classe MockMvcBuilders/| para crear o context param test fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o test iniciaO runner provido pelo Spring ira carregar todo contexto necessário para o controlEsse formato é mais considerado Интеграционный тест porque outros elementos do Spring e da aplicação (фильтры, Советы по тестированию сделайте Spring já são decorados com @ExtendWith(SpÉ utilizado a anotação @SprintBootTest . Тестирование вне сервера ringExtension.class ) Примечание: нет пружинной загрузки 2.1+, как указано в @… s) автоматическое управление. e (насмешки, фильтры, советы и т.д.). лизандо о том, как сделать весну. Mockito Extension Самос класс

Mockito Extension Samos a classe || MockMvcBuilders/| para crear o context param test fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o test iniciaO runner provido pelo Spring ira carregar todo contexto necessário para o controlEsse formato é mais considerado Интеграционный тест porque outros elementos do Spring e da aplicação (фильтры, Советы по тестированию || сделайте Spring já são decorados com || @ExtendWith(SpÉ utilizado a anotação || @SprintBootTest || . Реальный веб-сервер внешнего сервера, который не является официальным (зависит от того, что вы используете), издевается над вашими предпочтениями в отношении компонентов @SpringBootTest com MockMvc (sem webserver real) entes. Веб-среда || da anotação). о доблести и достоинстве || Весенняя официализация сегодня – это приложение для тех, кто зависит от обстоятельств, о том, как проверить, может ли это быть. r-тест ringExtension.class ) Примечание: нет пружинной загрузки 2.1+, как указано || @… s) sao adicionados automaticamente. e (насмешки, фильтры, советы и т.д.). лизандо о том, как сделать весну.

Расширение Mockito Само класс//создатели MockMvc//para crear o тест параметров контекста для выполнения задач в качестве необходимых условий: MockMvc com весенний контекст Подемос исполнитель о тесте iniciaO бегун Провидо Пело весна Ира Каррегар todo контекст для необходимости пункт о контроле формато é mais рассмотреть интеграционный тест porque outros elementos do Spring e да aplicação (фильтры, фильтры, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, элементы, Советы//делать весенние já são decorados com || @ExtendWith(spéticado a anotação || @SprintBootTest || . Внешний веб-сервер real pode ou não ser inicializado (зависит от d//É possível ainda утилизатор издевается над ou desativar alguns compon@SpringBootTest com MockMvc (реальный веб-сервер sem) для весенней инициализации тода апликасао сем для реального веб-сервера//да анотасао). o доблесть да проприедада |/Весна inicializa toda a aplicação com todas suas dependências, o que torna o teste mais lento. r Тестовое растяжение кольца.класс) Примечание: нет пружинной загрузки 2.1+, как anotaçoes//@… s) sao adicionados automaticamente. e (издевательства, фильтры, советы и т. д.). lizando o contexto do Spring.

Mockito Extension Samos a classe MockMvcBuilders/| para crear o context param test fornecendo todas as peças necessarias: MockMvc com Spring Context Podemos executar o test iniciaO runner provido pelo Spring ira carregar todo contexto necessário para o controlEsse formato é mais considerado Интеграционный тест porque outros elementos do Spring e da aplicação (фильтры, Советы по тестированию сделайте Spring já são decorados com @ExtendWith(SpÉ utilizado a anotação @SprintBootTest . Реальный веб-сервер внешнего сервера, который не является официальным (зависит от пользователя), который использует mocks или desativar alguns compon@SpringBootTest com MockMvc (sem webserver real), который использует anotação sem parâmetros ou com webEnvironment. O Spring inicializa toda a aplicação sem um веб-сервер real. es. webEnvironment

@SpringBootTest
@AutoConfigureJsonTesters
@AutoConfigureMockMvc
public class PetsControllerSpringBootMockTest {
    @Autowired
    private MockMvc mvc;

    @MockBean
    private PetsRepository petsRepository;

    // inicializado automaticamente pelo @AutoConfigureJsonTesters
    @Autowired
    private JacksonTester json;

    @Test
    public void should_return_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willReturn(Optional.of(new Pet(42, "Marley", "Wesley")));

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getContentAsString())
            .isEqualTo(
                json.write(new Pet(42, "Marley", "Wesley")).getJson()
            );
    }

    @Test
    public void should_return_not_found_for_non_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willThrow(new PetNotFoundException());

        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
        assertThat(response.getContentAsString()).isEmpty();
    }

    @Test
    public void should_create_new_pet() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    post("/pets")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(
                            json.write(new Pet("Marley", "Wesley")).getJson()
                        )
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());

        ArgumentCaptor argCaptor = ArgumentCaptor.forClass(Pet.class);
        verify(petsRepository).save(argCaptor.capture());
        Pet pet = argCaptor.getValue();

        assertThat(pet.getId()).isEqualTo(0);
        assertThat(pet.getName()).isEqualTo("Marley");
        assertThat(pet.getOwner()).isEqualTo("Wesley");
    }

    @Test
    public void should_add_api_version_header() throws Exception {
        MockHttpServletResponse response = mvc.perform(
                    get("/pets/42").accept(MediaType.APPLICATION_JSON)
                )
                .andReturn()
                .getResponse();

        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        assertThat(response.getHeaders("X-PETS-VERSION")).containsOnly("v1");
    }
}

Больше рекомендуется использовать MockMVC с расширением @SpringExtension потому что это более управляемой для тестирования контроллера конкретного.

@SpringBootTest com RestTemplate ou TestRestTemplate (реальный веб-сервер com)

O Spring инициализирует toda веб-сервер aplicaçao com um real (tomcat, jetty). Для тестирования мы используем RestTemplate или TestRestTemplate , который дает нам несколько возможностей для облегчения тестирования интеграции.

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class PetsControllerSpringBootTest {
    @MockBean
    private PetsRepository petsRepository;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void should_return_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willReturn(Optional.of(new Pet(42, "Marley", "Wesley")));

        ResponseEntity response = restTemplate.getForEntity("/pets/42", Pet.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getBody().equals(new Pet(42, "Marley", "Wesley")));
    }

    @Test
    public void should_return_not_found_for_non_existing_pet() throws Exception {
        given(petsRepository.findById(42))
                .willThrow(new PetNotFoundException());

        ResponseEntity response = restTemplate.getForEntity("/pets/42", Pet.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
        assertThat(response.getBody()).isNull();
    }

    @Test
    public void should_create_new_pet() throws Exception {
        ResponseEntity response = restTemplate.postForEntity("/pets",
                new Pet("Marley", "Wesley"), Pet.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);

        ArgumentCaptor argCaptor = ArgumentCaptor.forClass(Pet.class);
        verify(petsRepository).save(argCaptor.capture());
        Pet pet = argCaptor.getValue();

        assertThat(pet.getId()).isEqualTo(0);
        assertThat(pet.getName()).isEqualTo("Marley");
        assertThat(pet.getOwner()).isEqualTo("Wesley");
    }

    @Test
    public void should_add_api_version_header() throws Exception {
        ResponseEntity response = restTemplate.getForEntity("/pets/42", Pet.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getHeaders().get("X-PETS-VERSION")).containsOnly("v1");
    }
}

Примечание

Стоит отметить, что в тестах мы mockando класс PetsRepository потому что мы хотим проверить самостоятельно нашего API, здесь мы хотим проверить:

  • сериализации из-models
  • filters
  • проверки в контроллер
  • заголовки com ответа

Проект пример нет github .

Оригинал: “https://dev.to/wesleyegberto/spring-boot-estrategias-para-testar-rest-api-2nc6”