Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 14, 2022 01:17 pm GMT

3 motivos do porqu testes unitrios no so suficientes para Microservices com Spring Boot

Escrever testes automatizados j rotina para maioria dos times de tecnologia, porm, o que no te contaram que testar microsservios Spring Boot confiando em apenas de testes de unidade pode diminuir a qualidade do seu sistema. E hoje vou mostrar para voc 3 motivos que demostram que apenas testes unitrios no so suficientes para microsservios com Spring Boot.

O primeiro motivo que testes de unidade costumam ser escritos utilizando Mocks, e se voc esta instanciando seus Beans manualmente esta deixando de validar uma srie de comportamentos e configuraes relacionados ao contexto do Spring.

O segundo motivo que ao mockar as dependncias dos seus Beans, voc esta renunciando a validar o comportamento entre a integrao de um componente e outro. E isto pode fazer com que, falhas de conexo entre seu banco de dados relacional, mapeamentos de entidade da JPA/Hibernate e controle transacional nunca sejam executados. O impacto disto que se houver algum erro em alguma destas tarefas o seu cliente/usuario quem vai encontrar o bug em produo.

O terceiro motivo que voc esta deixando de validar os efeitos colaterais do seu componente de cdigo, isto significa, que voc no tem nenhuma garantia que inseriu um registro no banco, uma mensagem na fila, ou um arquivo no storage.

Para entender melhor, observe o cdigo abaixo, neste temos uma API REST que recebe informaes necessrias para o cadastro de um produto na base de dados.

@RestControllerpublic class CadastraProdutoController {    private final ProdutoRepository repository;    private final Logger LOGGER = LoggerFactory.getLogger(CadastraProdutoController.class);    public CadastraProdutoController(ProdutoRepository repository) {        this.repository = repository;    }    @PostMapping("/produtos")    @Transactional    public ResponseEntity<?> cadastrar(@RequestBody @Valid ProdutoRequest request) {        if (repository.existsBySku(request.getSku())) {            LOGGER.error("J existe um produto cadastrado para este sku {}", request);            throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, "Produto ja cadastrado");        }        Produto novoProduto = request.toModel();        repository.save(novoProduto);        LOGGER.info("Produto Cadastrado {}", novoProduto);        return ResponseEntity.status(CREATED).build();    }}

Um caso de teste de unidade para este Controller, focaria em validar se o contrato esta sendo respeitado, o que significa que instanciaramos um objeto do tipo ProdutoRequest, e executaramos a funo cadastrar, e por fim iremos validar se a resposta HTTP contm um Status 201 CREATED. Para realizar este teste necessrio que utilizaremos o Mockito para criar um duble do ProdutoRepository, dando comportamento para os mtodos: existsBySku e save. Abaixo tem o cdigo correspondente a este caso de teste.

@ExtendWith(value = MockitoExtension.class)class CadastraProdutoControllerUnitTest {    @Mock    private ProdutoRepository repository;    private CadastraProdutoController produtoController;    @BeforeEach    void setUp() {        this.produtoController = new CadastraProdutoController(repository);    }    @Test    @DisplayName("deve cadastrar um Produto")    void t1() {        //Cenario        ProdutoRequest produtoRequest = new ProdutoRequest(                "PlayStation 5",                "Console e 2 controles",                BigDecimal.TEN,                "123567"        );        when(repository.existsBySku(produtoRequest.getSku())).thenReturn(false);        when(repository.save(any(Produto.class))).thenReturn(produtoRequest.toModel());        //acao        ResponseEntity<?> response = produtoController.cadastrar(produtoRequest);        // validacao        assertEquals(HttpStatus.CREATED, response.getStatusCode());    }}

Por mais que parea que o caso de teste completo, ele no valida caractersticas essncias da nossa API. Como se ela atende, ao verbo POST, e a URI de "/produtos". No valida se as informaes recebidas no body da requisio HTTP so desserializadas em um objeto Java. Tambm no validado se as informaes referentes ao produto so registradas no Banco de Dados.

A verdade que diversos comportamentos indispensveis para o funcionamento do software so ignorados no caso de teste. E caso no funcionem como esperado, no sero detectados durante a execuo.

Um teste bem escrito para este Controller consideraria a integrao com Application Context do Spring Boot, o que garantiria que Beans de todas as camadas seriam instanciados, e se houver erros de configurao e mapeamento o teste j falharia imediatamente. Outra caracterstica essencial que a lgica de negcio execute de maneira similar a execuo do servidor, isto significa que a API deve ser exposta na Web, e que durante o teste uma requisio HTTP deve ser feita, o que garantiria que um banco de dados seria utilizado na execuo, ou seja, como efeito colateral da requisio, um registro deve ser criado na base de dados. Abaixo tem o cdigo correspondente a este caso de teste.

@SpringBootTest@ActiveProfiles("test")@AutoConfigureMockMvc(printOnlyOnFailure = false)class CadastraProdutoControllerIntegrationTest {    @Autowired    private ObjectMapper mapper;    @Autowired    private ProdutoRepository repository;    @Autowired    private MockMvc mockMvc;    @BeforeEach    void setUp() {        repository.deleteAll();    }    @Test    @DisplayName("deve cadastrar um Produto")    void t1() throws Exception {        //Cenario        ProdutoRequest produtoRequest = new ProdutoRequest(                "PlayStation 5",                "Console e 2 controles",                BigDecimal.TEN,                "123456"        );        String payload = toJson(produtoRequest);        MockHttpServletRequestBuilder request = post("/produtos")                .header(HttpHeaders.ACCEPT_LANGUAGE, "en")                .contentType(APPLICATION_JSON)                .content(payload);        //Acao        ResultActions response = mockMvc.perform(request);        //Validacao        response.andExpectAll(                status().isCreated()        );        assertEquals(1, repository.findAll().size(),                "deveria conter apenas um registro de produto"        );    }}

Concluso

Como visto anteriormente testes de integrao so mais assertivos que testes unitrios, pois, testes integrados favorecem que os diversos pontos de integrao sejam exercitados. Exercitar a integrao com contexto do Spring, favorece que validamos configurao das propriedades e Beans. Tambm favorece a validao do comportamento de integrao as camadas referente a Rede e Banco de Dados.

No contexto de sistemas distribudos e microsservios onde temos pequenas bases de cdigo e a maioria das operaes so referentes a entrada e sada (I/O) favorecer testes de unidades no ser suficientes para garantir o comportamento do seu software.

E se voc ainda tem dvida do que leu at aqui, remova todas as anotaes de um Controller e rode seus testes de unidade, e se nenhum teste quebrar me conta aqui nos comentrios.


Original Link: https://dev.to/jordihofc/3-motivos-do-porque-testes-unitarios-nao-sao-suficientes-para-microservices-com-spring-boot-33lk

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To