11
respostas

Está dando NullPointerException nas classes de testes: ValidacaoTutorComLimiteDeAdocoesTest e

Boa noite pessoal

Tudo bem?

Duas classes unitárias que foram mostrada na aula estão dando NullPointerException :

ValidacaoTutorComLimiteDeAdocoesTest:

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComLimiteDeAdocoesTest {
    @InjectMocks
    private ValidacaoTutorComLimiteDeAdocoes validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;


    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorAtingiuLimiteDe5Adocoes() {
        //Arrange
        given(adocaoRepository.countByTutorIdAndStatus(dto.idTutor(),StatusAdocao.APROVADO)).willReturn(5);

        //Act + Assert
        assertThrows(ValidacaoException.class,() ->validador.validar(dto));
    }

    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorNaoAtingiuLimiteDe5Adocoes() {
        //Arrange
        given(adocaoRepository.countByTutorIdAndStatus(dto.idTutor(),StatusAdocao.APROVADO)).willReturn(4);

        //Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }
}

ValidacaoTutorComAdocaoEmAndamentoTest:

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComAdocaoEmAndamentoTest {
    @InjectMocks
    private ValidacaoTutorComAdocaoEmAndamento validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;

    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento(){

        //ARRANGE
        given(adocaoRepository.existsByPetIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(true);

        //ACT + Assert
        assertThrows(ValidacaoException.class, () -> validador.validar(dto));

    }
    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento(){
        //Arrange
        given(adocaoRepository.existsByPetIdAndStatus(dto.idTutor(),StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(false);

        //Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }

}

Não tinha o método countByTutorIdAndStatus do AdocaoRepository e crei conforme a imagem:

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

Resultado dos teste unitários da classe ValidacaoTutorComLimiteDeAdocoesTest:

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

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

Resultado dos teste unitários da classe ValidacaoTutorComAdocaoEmAndamentoTest:

Insira aqui a descrição dessa imagem para ajudar na acessibilidadePoderia me ajudar?

Atenciosamente,

Marcos

11 respostas

Oi!

Confira nas classes sendo testadas (ValidacaoTutorComLimiteDeAdocoes e ValidacaoTutorComAdocaoEmAndamento) se te malgum atributo que não foi realizado o mock.

A princípio elas tem um atributo do tipo tutorRepository que não foi mockado nos testes e por isso estão null, causando o NullPointerExcpetion.

Bom dia, Rodrigo.

Tudo bem?

Eu coloquei TutorRepository nas classes: ValidacaoTutorComLimiteDeAdocoes e ValidacaoTutorComAdocaoEmAndamento e funcionou a classe ValidacaoTutorComAdocaoEmAndamento.

Na classe de teste ValidacaoTutorComLimiteDeAdocoesTest não funciona na classe ValidacaoTutorComLimiteDeAdocoes, conforme os códigos das classes e das imagens abaixo:

Código da classe ValidacaoTutorComLimiteDeAdocoes:

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

import br.com.alura.adopet.api.dto.SolicitacaoAdocaoDto;
import br.com.alura.adopet.api.exception.ValidacaoException;
import br.com.alura.adopet.api.model.Adocao;
import br.com.alura.adopet.api.model.StatusAdocao;
import br.com.alura.adopet.api.model.Tutor;
import br.com.alura.adopet.api.repository.AdocaoRepository;
import br.com.alura.adopet.api.repository.TutorRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ValidacaoTutorComLimiteDeAdocoes implements ValidacaoSolicitacaoAdocao {

    @Autowired
    private AdocaoRepository adocaoRepository;

    @Autowired
    private TutorRepository tutorRepository;
    
    public void validar(SolicitacaoAdocaoDto dto) {
        List<Adocao> adocoes = adocaoRepository.findAll();
        Tutor tutor = tutorRepository.getReferenceById(dto.idTutor());
        for (Adocao a : adocoes) {
            int contador = 0;
            if (a.getTutor() == tutor && a.getStatus() == StatusAdocao.APROVADO) {
                contador = contador + 1;
            }
            if (contador == 5) {
                throw new ValidacaoException("Tutor chegou ao limite máximo de 5 adoções!");
            }
        }
    }
}

Classe unitária ValidacaoTutorComLimiteDeAdocoesTest:

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComLimiteDeAdocoesTest {

@InjectMocks
private ValidacaoTutorComAdocaoEmAndamento validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private TutorRepository tutorRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;

    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento() {
        //Arrange
        given(adocaoRepository.existsByTutorIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(true);

        //Act + Assert
        assertThrows(ValidacaoException.class, () -> validador.validar(dto));
    }

    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento() {
        //Arrange
        given(adocaoRepository.existsByTutorIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(false);

        //Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }

}

Resultado dos teste unitários da classe ValidacaoTutorComLimiteDeAdocoesTest:

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

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

Atenciosamente,

Marcos

Agora você está com o mock correto do tutorRepository no teste e o problema mudou.

Nos seus 2 métodos de testes você faz essa configuração para o mock:

 given(adocaoRepository.existsByTutorIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(true);

Mas na classe ValidacaoTutorComLimiteDeAdocoes esse método não é chamado no adocaoRepository e por isso o Mockito acusa o problema. Os unicos métodos dos repositories sendo chamados na classe são esses:

adocaoRepository.findAll();

e

tutorRepository.getReferenceById(dto.idTutor());

Então nos testes eles que deveriam ser configurados.

Como configuraria esses método, professor Rodrigo?

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComLimiteDeAdocoesTest {

    @InjectMocks
    private ValidacaoTutorComLimiteDeAdocoes validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private TutorRepository tutorRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;

    @Mock
    private Tutor tutor;

    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento() {
        // Arrange
        var tutorId = 1L;
        when(dto.idTutor()).thenReturn(tutorId);
        when(tutorRepository.getReferenceById(tutorId)).thenReturn(tutor);
        
        var adocao1 = new Adocao();
        adocao1.setTutor(tutor);
        adocao1.setStatus(StatusAdocao.APROVADO);
       
        var adocao2 = new Adocao();
        adocao2.setTutor(tutor);
        adocao2.setStatus(StatusAdocao.APROVADO);
        
        var adocao3 = new Adocao();
        adocao3.setTutor(tutor);
        adocao3.setStatus(StatusAdocao.APROVADO);
        
        var adocao4 = new Adocao();
        adocao4.setTutor(tutor);
        adocao4.setStatus(StatusAdocao.APROVADO);
        
        var adocao5 = new Adocao();
        adocao5.setTutor(tutor);
        adocao5.setStatus(StatusAdocao.APROVADO);
        
        var adocoes = List.of(adocao1, adocao2, adocao3, adocao4, adocao5);
        when(adocaoRepository.findAll()).thenReturn(adocoes);

        // Act + Assert
        assertThrows(ValidacaoException.class, () -> validador.validar(dto));
    }

    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento() {
        // Arrange
        Long tutorId = 1L;
        when(dto.idTutor()).thenReturn(tutorId);
        when(tutorRepository.getReferenceById(tutorId)).thenReturn(tutor);
        when(adocaoRepository.findAll()).thenReturn(Collections.emptyList());

        // Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }
}

Explicação:

1. naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento():

  • Arrange:

    • Definimos um tutorId e configuramos o mock do dto para retornar esse ID quando idTutor() for chamado.
    • Configuramos o mock do tutorRepository para retornar um objeto Tutor mockado quando getReferenceById(tutorId) for chamado.
    • Criamos cinco instâncias de Adocao com o status APROVADO e associadas ao mesmo tutor mockado.
    • Criamos uma lista com essas cinco adoções.
    • Configuramos o mock do adocaoRepository para retornar essa lista quando findAll() for chamado.
  • Act + Assert:

    • Chamamos o método validar() do validador, passando o dto como argumento.
    • Utilizamos assertThrows para verificar se uma exceção do tipo ValidacaoException é lançada, indicando que a validação falhou.

2. deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento():

  • Arrange:

    • Definimos um tutorId e configuramos o mock do dto para retornar esse ID quando idTutor() for chamado.
    • Configuramos o mock do tutorRepository para retornar um objeto Tutor mockado quando getReferenceById(tutorId) for chamado.
    • Configuramos o mock do adocaoRepository para retornar uma lista vazia quando findAll() for chamado, simulando um cenário onde o tutor não possui nenhuma adoção em andamento.
  • Act + Assert:

    • Chamamos o método validar() do validador, passando o dto como argumento.
    • Utilizamos assertDoesNotThrow para verificar se nenhuma exceção é lançada, indicando que a validação passou com sucesso.

Observações:

  • É importante garantir que o número de adoções com status APROVADO associadas ao tutor seja igual ou superior a 5 no primeiro teste para que a validação falhe.
  • No segundo teste, podemos utilizar uma lista vazia para simular a ausência de adoções em andamento, mas também poderíamos utilizar uma lista com adoções que não violem a regra de validação (por exemplo, adoções com status diferente de APROVADO ou associadas a outros tutores).

Com essas configurações, os testes devem cobrir os dois cenários possíveis para a validação do limite de adoções.

Só o método naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento() não funcionou:

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

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

Ah, acho que tem um problema na lógica do método, com essa linha que declara o contador:

int contador = 0;

Ela deve ficar fora do loop for, se não será reiniciada a cada iteração. Altere para:

public void validar(SolicitacaoAdocaoDto dto) {
    List<Adocao> adocoes = adocaoRepository.findAll();
    Tutor tutor = tutorRepository.getReferenceById(dto.idTutor());
    int contador = 0;
    for (Adocao a : adocoes) {
        if (a.getTutor() == tutor && a.getStatus() == StatusAdocao.APROVADO) {
            contador = contador + 1;
        }
        if (contador == 5) {
            throw new ValidacaoException("Tutor chegou ao limite máximo de 5 adoções!");
        }
    }
}

Os métodos dos teste unitários da classe ValidacaoTutorComAdocaoEmAndamentoTest estão quebrando:

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

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

Segue a classe ValidacaoTutorComAdocaoEmAndamentoTest:

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

import br.com.alura.adopet.api.dto.SolicitacaoAdocaoDto;
import br.com.alura.adopet.api.exception.ValidacaoException;
import br.com.alura.adopet.api.model.StatusAdocao;
import br.com.alura.adopet.api.repository.AdocaoRepository;
import br.com.alura.adopet.api.repository.TutorRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import org.mockito.junit.jupiter.MockitoExtension;


import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.BDDMockito.given;

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComAdocaoEmAndamentoTest {
    @InjectMocks
    private ValidacaoTutorComAdocaoEmAndamento validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;

    @Mock
    private TutorRepository tutorRepository;

    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento() {
        //Arrange
        given(adocaoRepository.existsByTutorIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(true);

        //Act + Assert
        assertThrows(ValidacaoException.class, () -> validador.validar(dto));
    }

    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento() {
        //Arrange
        given(adocaoRepository.existsByTutorIdAndStatus(dto.idTutor(), StatusAdocao.AGUARDANDO_AVALIACAO)).willReturn(false);

        //Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }

}

Segue a classe ValidacaoTutorComAdocaoEmAndamento:

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

import br.com.alura.adopet.api.dto.SolicitacaoAdocaoDto;
import br.com.alura.adopet.api.exception.ValidacaoException;
import br.com.alura.adopet.api.model.Adocao;
import br.com.alura.adopet.api.model.StatusAdocao;
import br.com.alura.adopet.api.model.Tutor;
import br.com.alura.adopet.api.repository.AdocaoRepository;
import br.com.alura.adopet.api.repository.TutorRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ValidacaoTutorComAdocaoEmAndamento implements ValidacaoSolicitacaoAdocao {

    @Autowired
    private AdocaoRepository adocaoRepository;

    @Autowired
    private TutorRepository tutorRepository;

    public void validar(SolicitacaoAdocaoDto dto) {
        List<Adocao> adocoes = adocaoRepository.findAll();
        Tutor tutor = tutorRepository.getReferenceById(dto.idTutor());
        for (Adocao a : adocoes) {
            if (a.getTutor() == tutor && a.getStatus() == StatusAdocao.AGUARDANDO_AVALIACAO) {
                throw new ValidacaoException("Tutor já possui outra adoção aguardando avaliação!");
            }
        }
    }

}

Atenciosamente,

Marcos

Similar ao problema da outra classe de testes:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ValidacaoTutorComAdocaoEmAndamentoTest {
    
    @InjectMocks
    private ValidacaoTutorComAdocaoEmAndamento validador;

    @Mock
    private AdocaoRepository adocaoRepository;

    @Mock
    private SolicitacaoAdocaoDto dto;

    @Mock
    private TutorRepository tutorRepository;

    @Mock
    private Tutor tutor;

    @Test
    void naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento() {
        // Arrange
        var tutorId = 1L;
        var adocao = new Adocao();
        adocao.setTutor(tutor);
        adocao.setStatus(StatusAdocao.AGUARDANDO_AVALIACAO);
        var adocoes = Collections.singletonList(adocao);

        when(dto.idTutor()).thenReturn(tutorId);
        when(tutorRepository.getReferenceById(tutorId)).thenReturn(tutor);
        when(adocaoRepository.findAll()).thenReturn(adocoes);

        // Act + Assert
        assertThrows(ValidacaoException.class, () -> validador.validar(dto));
    }

    @Test
    void deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento() {
        // Arrange
        var tutorId = 1L;

        when(dto.idTutor()).thenReturn(tutorId);
        when(tutorRepository.getReferenceById(tutorId)).thenReturn(tutor);
        when(adocaoRepository.findAll()).thenReturn(Collections.emptyList());

        // Act + Assert
        assertDoesNotThrow(() -> validador.validar(dto));
    }
}

Explicação:

  1. naoDeveriaPermitirSolicitacaoDeAdocaoTutorComAdocaoEmAndamento:

    • Arrange:
      • Criamos um objeto Adocao com status AGUARDANDO_AVALIACAO e o tutor mockado.
      • Configuramos o adocaoRepository para retornar uma lista contendo essa Adocao.
      • Configuramos o dto para retornar um ID de tutor e o tutorRepository para retornar o tutor mockado quando chamado com esse ID.
    • Act + Assert:
      • Usamos assertThrows para verificar se ValidacaoException é lançada ao chamar validador.validar(dto).
  2. deveriaPermitirSolicitacaoDeAdocaoTutorSemAdocaoEmAndamento:

    • Arrange:
      • Configuramos o adocaoRepository para retornar uma lista vazia, simulando que não há adoções em andamento.
      • Configuramos o dto para retornar um ID de tutor e o tutorRepository para retornar o tutor mockado.
    • Act + Assert:
      • Usamos assertDoesNotThrow para verificar se nenhuma exceção é lançada ao chamar validador.validar(dto).

Obrigado pela explicação, Rodrigo!

Para saber se o teste unitário esta cobrindo 100% a classe tem rodar os teste unitários com Coverage?

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

Atenciosamente,

Marcos

Isso mesmo.