Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

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.