Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

[Bug] TESTES AUTOMATIZADOS CONTROLLER

Oi galera!, meu teste do forum web está com algum problema, na hora de testar a controller, ele está tentando inserir dados no banco de dados real, como faço para evitar isso?, segue a classe e o log:

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
class RespostaControllerTest {

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<DadosCadastroRespostas> dadosCadastroRespostasJt;

    @Autowired
    private JacksonTester<DadosDetalhamentoResposta> dadosDetalhamentoRespostaJt;

    @MockBean
    private ValidarExistenciaTopico vet;

    @MockBean
    private ValidarUsuarioResposta vur;

    @Test
    @DisplayName("POST de respostas sem corpo na requisição deveria retornar BAD_REQUEST")
    @WithMockUser
    void cadastrarRespostaCenarioUm() throws Exception {
        var response = mvc.perform(post("/respostas"))
                .andReturn().getResponse();

        assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatus());
    }

    @Test
    @DisplayName("POST de respostas válidas deve retornar OK")
    @WithMockUser
    void cadastrarRespostaCenarioDois() throws Exception {
        var data = LocalDateTime.now().plusHours(2);

        var dados = new DadosCadastroRespostas("Testando", 1L, 1L, data, "Essa é a solução");

        doNothing().when(vet).validar(any());
        doNothing().when(vur).validar(any());

        var response = mvc.perform(
                post("/respostas")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(dadosCadastroRespostasJt.write(dados).getJson()))
                .andReturn().getResponse();

        var jsonEsperado = dadosDetalhamentoRespostaJt.write(
                new DadosDetalhamentoResposta(null, "Testando", data, "Essa é a solução", 1L)).getJson();

        assertThat(response.getContentAsString()).isEqualTo(jsonEsperado);
        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
    }
}
", "%TESTC  1 v2
%TSTTREE2,com.api.forumweb.app.controller.RespostaControllerTest,true,1,false,1,RespostaControllerTest,,[engine:junit-jupiter]/[class:com.api.forumweb.app.controller.RespostaControllerTest]
%TSTTREE3,cadastrarRespostaCenarioDois(com.api.forumweb.app.controller.RespostaControllerTest),false,1,false,2,POST de respostas válidas deve retornar OK,,[engine:junit-jupiter]/[class:com.api.forumweb.app.controller.RespostaControllerTest]/[method:cadastrarRespostaCenarioDois()]
%TESTS  3,cadastrarRespostaCenarioDois(com.api.forumweb.app.controller.RespostaControllerTest)

%FAILED 3,cadastrarRespostaCenarioDois(com.api.forumweb.app.controller.RespostaControllerTest)
%EXPECTS
"{"id":null,"mensagem":"Testando","dataCriacao":"2024-07-10T18:10:14.3738766","solucao":"Essa é a solução","idUsuario":1}"
%EXPECTE
%ACTUALS
"could not execute statement [Cannot add or update a child row: a foreign key constraint fails (`artmantel_forum_db`.`respostas`, CONSTRAINT `respostas_ibfk_1` FOREIGN KEY (`id_topico`) REFERENCES `topicos` (`id`))] [insert into respostas (data_criacao,mensagem,solucao,id_topico,id_usuario) values (?,?,?,?,?)]; SQL [insert into respostas (data_criacao,mensagem,solucao,id_topico,id_usuario) values (?,?,?,?,?)]; constraint [null]"
%ACTUALE
%TRACES 
org.opentest4j.AssertionFailedError: 
expected: "{"id":null,"mensagem":"Testando","dataCriacao":"2024-07-10T18:10:14.3738766","solucao":"Essa é a solução","idUsuario":1}"
 but was: "could not execute statement [Cannot add or update a child row: a foreign key constraint fails (`artmantel_forum_db`.`respostas`, CONSTRAINT `respostas_ibfk_1` FOREIGN KEY (`id_topico`) REFERENCES `topicos` (`id`))] [insert into respostas (data_criacao,mensagem,solucao,id_topico,id_usuario) values (?,?,?,?,?)]; SQL [insert into respostas (data_criacao,mensagem,solucao,id_topico,id_usuario) values (?,?,?,?,?)]; constraint [null]"
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at com.api.forumweb.app.controller.RespostaControllerTest.cadastrarRespostaCenarioDois(RespostaControllerTest.java:80)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

%TRACEE 
%TESTE  3,cadastrarRespostaCenarioDois(com.api.forumweb.app.controller.RespostaControllerTest)

%RUNTIME33644"
4 respostas

Oi Fernando!

Entendo sua frustração ao ver seus testes interagindo com o banco de dados real. Para evitar isso, você pode utilizar um banco de dados em memória, como o H2, que é bastante comum em testes com Spring Boot. Vou te mostrar como configurar isso.

Primeiro, adicione a dependência do H2 no seu pom.xml:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

Em seguida, configure o banco de dados H2 para ser usado nos testes. Crie ou edite o arquivo application-test.properties (ou application.yml se você usar YAML) na pasta src/test/resources:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Certifique-se de que sua classe de teste esteja anotada com @ActiveProfiles("test") para que o Spring Boot use as configurações de teste ao rodar os testes:

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@ActiveProfiles("test")
class RespostaControllerTest {
    // Seu código de teste aqui
}

Além disso, é uma boa prática utilizar a anotação @Transactional nos testes para garantir que qualquer alteração no banco de dados seja revertida após a execução do teste:

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@ActiveProfiles("test")
@Transactional
class RespostaControllerTest {
    // Seu código de teste aqui
}

Com essas configurações, seus testes deverão utilizar o banco de dados em memória H2, evitando interações com o banco de dados real.

Espero ter ajudado e bons estudos!

Oi Rodrigoo, obrigado pela respostaaa, então, eu estava tentando realizar esses testes igual no curso, testando a controller de maneira isolada, mas nesse caso então devo utilizar banco de dados em memória e cadastrar as informações antes e realizar os testes depois né

Ah sim, para não usar banco precisa injetar o mock das dependências do controller.

No seu teste você injetou com @MockBean as classes de validação, mas o controller deve estar chamando algum repository ou service, que também precisa ser injetado com @MockBean, para que o banco de dados real não seja utilizado.

solução!

Conseguiiiiii, foi só adicionar Mock da respostaRepository, Brigado proffff