5
respostas

[Dúvida] Como faz o teste unitário quando exceção ValidacaoException na classe TutorController?

Boa tarde, pessoal.

Rodei os teste unitários da classe TutorControllerTest com coverage e não está cobrindo 100% a classe TutorController:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Como faz o teste unitário quando exceção ValidacaoException na classe TutorController?

Classe TutorController:

package br.com.alura.adopet.api.controller;

import br.com.alura.adopet.api.dto.AtualizacaoTutorDto;
import br.com.alura.adopet.api.dto.CadastroTutorDto;
import br.com.alura.adopet.api.exception.ValidacaoException;
import br.com.alura.adopet.api.service.TutorService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/tutores")
public class TutorController {

    @Autowired
    private TutorService service;

    @PostMapping
    @Transactional
    public ResponseEntity<String> cadastrar(@RequestBody @Valid CadastroTutorDto dto) {
        try {
            service.cadastrar(dto);
            return ResponseEntity.ok().build();
        } catch (ValidacaoException exception) {
            return ResponseEntity.badRequest().body(exception.getMessage());
        }
    }

    @PutMapping
    @Transactional
    public ResponseEntity<String> atualizar(@RequestBody @Valid AtualizacaoTutorDto dto) {
        try {
            service.atualizar(dto);
            return ResponseEntity.ok().build();
        } catch (ValidacaoException exception) {
            return ResponseEntity.badRequest().body(exception.getMessage());
        }
    }

}

Atenciosamente,

Marcos

5 respostas

Olá, Marcos! Tudo bem?

Para testar a exceção ValidacaoException na classe TutorController, você pode criar um teste unitário que simule uma situação onde essa exceção seria lançada. Aqui está um exemplo de como você pode fazer isso usando MockMvc:

  1. Configure o Mock: Use o Mockito para simular o comportamento do TutorService para lançar a exceção quando um método específico for chamado.

  2. Crie o teste: Simule uma requisição que causaria a exceção e verifique se o código HTTP 400 é retornado.

Aqui está um exemplo de como poderia ser feito:

@Test
void deveriaDevolverCodigo400QuandoValidacaoExceptionForLancada() throws Exception {
    // Arrange
    String json = """
            {
                "nome": "Nome inválido",
                "telefone": "telefone inválido",
                "email": "email@invalido"
            }
            """;

    // Simula o lançamento da exceção quando o método cadastrar for chamado
    doThrow(new ValidacaoException("Dados inválidos"))
            .when(service).cadastrar(any(CadastroTutorDto.class));

    // Act
    MockHttpServletResponse response = mockMvc.perform(
            post("/tutores")
                    .content(json)
                    .contentType(MediaType.APPLICATION_JSON)
    ).andReturn().getResponse();

    // Assert
    assertEquals(400, response.getStatus());
    assertEquals("Dados inválidos", response.getContentAsString());
}

Explicação:

  • doThrow: Usado para simular o lançamento de uma exceção quando um método específico é chamado.
  • mockMvc.perform: Simula uma requisição HTTP POST para o endpoint /tutores.
  • assertEquals: Verifica se o código de status HTTP é 400 e se a mensagem de erro está correta.

Com esse teste, você deve conseguir cobrir o cenário onde a ValidacaoException é lançada.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Boa tarde, Armano.

Estou bem e vc?

O código do teste unitário que você compartilhou não deu certo não deu certo:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Segue o código da classe TutorControllerTest:

@SpringBootTest
@AutoConfigureMockMvc
class TutorControllerTest {

    @MockBean
    private TutorService service;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void deveriaDevolverCodigo200ParaRequisicaoDeCadastrarTutor() throws Exception {
        //Arrange
        String json = """
                {
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-9090",
                    "email": "email@example.com.br"
                }
                """;
        //Act
        MockHttpServletResponse response = mockMvc.perform(
                post("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(200,response.getStatus());
    }

    @Test
    void deveriaDevolverCodigo400ParaRequisicaoCadastrarTutorDadosInvalidos() throws Exception {
        //Arrange
        String json = """
                {
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-90900",
                    "email":"email@example.com.br"
                }
                """;

        //Act
        MockHttpServletResponse response = mockMvc.perform(
                post("/tutores")
                        .contentType(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(400,response.getStatus());
    }

    @Test
    void deveriaDevolverCodigo200ParaRequisicaoDeAtualizarTutor() throws Exception {
        //Arrange
        String json = """
                {
                    "id" : "1",
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-9090",
                    "email": "email@example.com"
                }
                """;

        //Act
        MockHttpServletResponse response = mockMvc.perform(
                put("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(200,response.getStatus());
    }

    @Test
    void deveriaDevolverCodigo400ParaRequisicaoDeAtualizarTutor() throws Exception {
        //Arrange
        String json = """
                {
                    "id" : "2",
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-90900",
                    "email":"email@example.com.br"
                }
                """;

        //Act
        MockHttpServletResponse response = mockMvc.perform(
                put("/tutores")
                        .contentType(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(400,response.getStatus());
    }

    @Test
    void deveriaDevolverCodigo400QuandoValidacaoExceptionForLancada() throws Exception {
        // Arrange
        String json = """
            {
                "nome": "Nome inválido",
                "telefone": "telefone inválido",
                "email": "email@invalido"
            }
            """;

        // Simula o lançamento da exceção quando o método cadastrar for chamado
        doThrow(new ValidacaoException("Dados inválidos"))
                .when(service).cadastrar(any(CadastroTutorDto.class));

        // Act
        MockHttpServletResponse response = mockMvc.perform(
                post("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        // Assert
        assertEquals(400, response.getStatus());
        assertEquals("Dados inválidos", response.getContentAsString());
    }
}

Bom dia, Marcos!

Peço desculpas pela demora em responder e por passar um teste que acabou ocasionando um erro.

Ao menos no meu ambiente o erro não aconteceu, mas ao testar novamente percebi que o teste que lhe passei também não cobriria 100% da classe TutorController.

Então, busquei outra alternativa, mudando até mesmo a estrutura do teste para certificar que cobriria totalmente a classe:

  1. Primeiro você precisa adicionar essas duas annotations com injeção no início do seu arquivo:

        @InjectMocks
        private TutorController tutorController;
    
        @BeforeEach
        public void setUp() {
            MockitoAnnotations.openMocks(this);
    }
    
  2. Agora, altere o seu primeiro teste de exceção para ficar da seguinte forma:

        @Test()
        void deveriaDevolverCodigo400ParaRequisicaoCadastrarTutorDadosInvalidos() throws Exception {
            // Arrange
            CadastroTutorDto cadastroDto = new CadastroTutorDto(null, null, null);
            doThrow(new ValidacaoException("Erro de validação")).when(service).cadastrar(cadastroDto);
    
            // Act
            ResponseEntity<String> response = tutorController.cadastrar(cadastroDto);
    
            // Assert
            assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
            assertEquals("Erro de validação", response.getBody());
        }
    
  3. Por fim, no seu segundo teste, também altere para ficar assim:

        @Test
        void deveriaDevolverCodigo400ParaRequisicaoDeAtualizarTutor() throws Exception {
            // Arrange
            AtualizacaoTutorDto atualizacaoDto = new AtualizacaoTutorDto(null, null, null, null);
            doThrow(new ValidacaoException("Erro de validação")).when(service).atualizar(atualizacaoDto);
    
            // Act
            ResponseEntity<String> response = tutorController.atualizar(atualizacaoDto);
    
            // Assert
            assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
            assertEquals("Erro de validação", response.getBody());
        }
    

Ao fazer as alterações e realizar o teste de cobertura novamente ele deve dar 100%.

Caso tenha mais algum problema estarei à disposião!

Bom dia, Armano

Eu fiz as alterações e o teste unitário da "deveriaDevolverCodigo400QuandoValidacaoExceptionForLancada()" continua não funcionado:

@Test
    void deveriaDevolverCodigo400QuandoValidacaoExceptionForLancada() throws Exception {
        // Arrange
        String json = """
            {
                "nome": "Nome inválido",
                "telefone": "telefone inválido",
                "email": "email@invalido"
            }
            """;

        // Simula o lançamento da exceção quando o método cadastrar for chamado
        doThrow(new ValidacaoException("Dados inválidos"))
                .when(service).cadastrar(any(CadastroTutorDto.class));

        // Act
        MockHttpServletResponse response = mockMvc.perform(
                post("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        // Assert
        assertEquals(400, response.getStatus());
        assertEquals("Dados inválidos", response.getContentAsString());
    }

Resposta do erro:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Opa, Marcos!

Acho que houve uma pequena confusão, esse método era o que eu havia passado para você no primeiro momento, mas estava causando o erro que você compartilhou e não cobria corretamente todo o controller. Com isso, você pode retirá-lo, os outros dois testes já fazem toda a tarefa que faltava para cobrir Controller Tutor.

Sua classe de testes deve estar assim:

package br.com.alura.adopet.api.controller;

import br.com.alura.adopet.api.dto.AtualizacaoTutorDto;
import br.com.alura.adopet.api.dto.CadastroTutorDto;
import br.com.alura.adopet.api.exception.ValidacaoException;
import br.com.alura.adopet.api.service.TutorService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.doThrow;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;

@SpringBootTest
@AutoConfigureMockMvc
class TutorControllerTest {

    @InjectMocks
    private TutorController tutorController;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @MockBean
    private TutorService service;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void deveriaDevolverCodigo200ParaRequisicaoDeCadastrarTutor() throws Exception {
        //Arrange
        String json = """
                {
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-9090",
                    "email": "email@example.com.br"
                }
                """;
        //Act
        MockHttpServletResponse response = mockMvc.perform(
                post("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(200,response.getStatus());
    }

    @Test()
    void deveriaDevolverCodigo400ParaRequisicaoCadastrarTutorDadosInvalidos() throws Exception {
        // Arrange
        CadastroTutorDto cadastroDto = new CadastroTutorDto(null, null, null);
        doThrow(new ValidacaoException("Erro de validação")).when(service).cadastrar(cadastroDto);

        // Act
        ResponseEntity<String> response = tutorController.cadastrar(cadastroDto);

        // Assert
        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertEquals("Erro de validação", response.getBody());
    }

    @Test
    void deveriaDevolverCodigo200ParaRequisicaoDeAtualizarTutor() throws Exception {
        //Arrange
        String json = """
                {
                    "id" : "1",
                    "nome": "Rodrigo",
                    "telefone": "(21)0000-9090",
                    "email": "email@example.com"
                }
                """;

        //Act
        MockHttpServletResponse response = mockMvc.perform(
                put("/tutores")
                        .content(json)
                        .contentType(MediaType.APPLICATION_JSON)
        ).andReturn().getResponse();

        //Assert
        assertEquals(200,response.getStatus());
    }
    
    @Test
    void deveriaDevolverCodigo400ParaRequisicaoDeAtualizarTutor() throws Exception {
        // Arrange
        AtualizacaoTutorDto atualizacaoDto = new AtualizacaoTutorDto(null, null, null, null);
        doThrow(new ValidacaoException("Erro de validação")).when(service).atualizar(atualizacaoDto);

        // Act
        ResponseEntity<String> response = tutorController.atualizar(atualizacaoDto);

        // Assert
        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertEquals("Erro de validação", response.getBody());
    }

}

Se tiver mais algum problema estarei aqui!