JUnitTest

Fiz as classes de Etidade, de Repository e Controller.

Fui fazer a JUnit, mas não passa e dá erro java.lang.NullPointerException.

Mas ai para tirar outra duvida, fiz o HTML, chamando as mesmas classes do Repository e funcionou, isto é, persistiu.

O que posso estar fazendo de errado na classe de testes ?

Como você está usando Spring, eu acredito que você tá usando injeção de dependência, certo?

No teste de unidade, não tem o Spring pra injetar os objetos que teus objetos precisam para funcionar, e por isso tá dando NullPointerException. Você precisa injetar tudo manualmente. As vezes, o objeto a ser injetado é muito complexo para se criar, e o propósito do unit test é ser algo simples de fazer. É aqui que entra o conceito de mock objects e frameworks como o Mockito.

Dá uma olhada aqui se quiser:

Mockito:

http://site.mockito.org/

Então, tenho que colocar no pom do projeto a dependência do Mock ?

Assim não utilizarei o JUnit, ou é um complemento por causa do spring ?

Isso, você precisa de um framework para construir objetos fake (ou mock objects). Eu gosto muito do Mockito, mas tem outros também.[quote=“guilhermebhte, post:3, topic:344622”]
Assim não utilizarei o JUnit, ou é um complemento por causa do spring ?
[/quote]

Vai usar o JUnit! O propósito do JUnit é simplesmente executar os teus testes. O mockito vai ser um recurso para facilitar o teste. Vou fazer um exemplo pra você ver.

Me perdoe pela ferrugem nos pontos do Spring, porque nunca mexi a fundo com ele, mas acredito que vai dar para entender.

Imagine que você tem uma classe, sei lá, um Controller, e quer fazer testes unitários nele. Vamos começar pela definição do Controller:

class MeuController {
    @Autowire (acho que é essa a anotação de injeção)
    private Repositorio repositorio;

    // esse método vai ser utilizado no teste
    public void setRepositorio(Repositorio repositorio) {
        this.repositorio = repositorio;
    }

    public int contaAlgumaCoisa() {
        List listaDeCoisas = repositorio.getCoisas();
        return listaDeCoisas.size();
    }
}

No teste, podemos fazer assim:

class MeuControllerTest {
    private final Repositorio fake = mock(Repositorio.class); // mock é um método do Mockito
    private final MeuController controller = new MeuController();

    @Before // esse método é executado antes de cada teste dessa classe
    public void setUp() {
        controller.setRepositorio(fake);
    }

    @Test
    public void contaAlgumaCoisaDeveRetornarAContagemCerta() {
        Lista listaDeCoisas = Arrays.asList(coisa1, coisa2, coisa3);
        doReturn(listaDeCoisas).when(fake).getCoisas(); // métodos do mockito. Aqui você tá dizendo que quando alguém chamar o método getCoisas() no objeto fake, é pra retornar listaDeCoisas
        assertThat(controller.contaAlgumaCoisa(), is(listaDeCoisas.size())); // métodos do junit e do hamcrest (framework com matchers, tipo o is()), que verificam se a contagem retornada é a esperada
    }
}

Eu não gosto muito da abordagem de utilizar um método set para injetar as dependências, porque é meio contra um principio de OO chamado de “Good Citizen”, ou “Bom Cidadão”. Esse princípio diz que um objeto, após ser construído (pelo construtor), deve estar em estado perfeito, pronto para ser utilizado. Quando a gente utiliza um método separado do construtor para compor o objeto, basta esquecer de chamar o método que o objeto fica em um estado perigoso (perigo de acontecer NullPointerException ou outras coisas inesperadas), como aconteceu com você.

Eu não sei se tem como fazer isso no Spring, no Java EE praticamente não dá, que é injetar dependências no construtor, e não nas variáveis da classe. Seria algo assim:

class MeuController {
    private Repositorio repositorio;

    MeuController(@Autowire repositorio) {
        this.repositorio = repositorio;
    }

    public int contaAlgumaCoisa() {
        List listaDeCoisas = repositorio.getCoisas();
        return listaDeCoisas.size();
    }
}

Dessa forma, não tem como construir o objeto sem passar a dependência (ou passar null, que é uma decisão explícita do programador, e não um esquecimento). No teste, não precisaria do @Before setando a dependência no objeto também, daria pra fazer direto assim:

class MeuControllerTest {
    private final Repositorio fake = mock(Repositorio.class); // mock é um método do Mockito
    private final MeuController controller = new MeuController(fake);
    // n precisa do @Before void setUp(){...}
    @Test
    ...
}

Porém, é uma limitação das ferramentas. Acredito que isso seja vencido com o tempo. Uma alternativa é definir dois construtores, um vazio (para o Spring utilizar) e um com as dependências, para os programadores utilizarem. Mas ainda assim, o fato de ter o construtor vazio deixa brecha pra erro.

Não sei se o Spring constrói os objetos se o construtor vazio estiver como protected ou private. Se ele fizer isso, dá para proibir o acesso ao construtor vazio utilizando um desses modificadores de acesso. Mas aí depende muito da ferramenta e eu não sei falar praticamente nada sobre Spring hahahaha

Espero que tenha dado para entender!

Blz