Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Solucionado (ver solução)

Ajuda com teste que lança exceção

Boa tarde amigos,

Estou com um teste unitário para fazer e não consigo encontrar uma forma de fazê-lo.

Criei um método que recebe um objeto e utilizando a API de reflection do Java, retorna se todos os atributos públicos daquele objeto são nulos.

    public static boolean allPublicFieldsAreNull(Object object) {
        if (object == null) {
            return false;
        }

        for (Field field : object.getClass().getFields()) {
            try {
                if (field.get(object) != null) {
                    return false;
                }
            } catch (IllegalAccessException e) {
                return false;
            }
        }

        return true;
    }

E para testar este método, criei os seguintes testes unitários:

O primeiro verifica o parâmetro de entrada nulo.

    @Test
    public void allPublicFieldsAreNull_should_return_false_because_parameterIsNull() {
        assertThat(ObjectUtils.allPublicFieldsAreNull(null)).isFalse();
    }

O segundo verifica o retorno TRUE.

    @Test
    public void allPublicFieldsAreNull_should_return_true() {
        assertThat(ObjectUtils.allPublicFieldsAreNull(new MyObject())).isTrue();
    }

O terceiro simula um atributo não nulo, para verificar o retorno FALSE.

    @Test
    public void allPublicFieldsAreNull_should_return_false() {
        final MyObject data = new MyObject();
        data.id = 123;

        assertThat(ObjectUtils.allPublicFieldsAreNull(data)).isFalse();
    }

Até aqui, tudo lindo, porém, estou precisando verificar também, quando a exceção ocorre, mas, já tentei de diversas formas e não consigo fazer funcionar.

Segue alguns testes que tentei fazer:

    @Test
    public void allPublicFieldsAreNull_should_return_false_because_anExceptionHappens() throws NoSuchFieldException {
        final SusData mock = mock(SusData.class);

        doThrow(new Exception()).when(mock).getClass().getField("id");

        assertThat(ObjectUtils.allPublicFieldsAreNull(mock)).isFalse();
    }

e

    @Test
    public void allPublicFieldsAreNull_should_return_false_because_anExceptionHappens() throws IllegalAccessException {
        final SusData mock = mock(SusData.class);

        doThrow(new Exception()).when(mock).getClass().getFields()[0].get(mock);

        assertThat(ObjectUtils.allPublicFieldsAreNull(mock)).isFalse();
    }

Os métodos não geram nenhum erro, mas também não lançam a exceção, fazendo o retorno ser incorreto.

Alguém saberia me ajudar?

5 respostas

Boa noite, Ivan! Como vai?

Eu não entendi muito bem! Nos dois últimos casos onde vc disse que não obteve o desejado, o método ObjectUtils.allPublicFieldsAreNull() deveria retornar o que? E o que está sendo retornado na prática? O assert que vc está fazendo está devolvendo qual resultado?

Com base nessas respostas eu vou poder entender melhor a situação para poder te ajudar!

Grande abraço e bons estudos, meu aluno!

solução

Teste

Ola Gabriel,

O método ObjectUtils.allPublicFieldsAreNull() retorna um boleano. Ele analisa o objeto enviado no parâmetro para verificar se todos os atributos público dele são NULOS. Para isso estou usando a API de Reflection do Java, usando o método .getClass().getFields() para obter os atributos públicos e depois o método get() para obter o valor do atributo. O que estou tentando fazer é forçar a geração da exceção IllegalAccessException para testar este pedaço do código.

} catch (IllegalAccessException e) {
    return false;
}

Tentei usando o when().thenThrow() e o doThrow().when(), mas em nenhum dos casos, ele reconheceu a exceção que eu forcei na mão.

Oi Ivan! Bom dia! Tudo bem?

Adoraria ajudar com seu problema, contudo penso que não entendi bem a proposta do seu teste.

Você construiu um cenário de teste onde todos os atributos públicos precisam estar nulos? Ou não podem ser nulos?

Apenas um direcionamento: Entender o que queremos testar é fundamental para escrevermos testes de qualidade e relevância.

De qualquer forma existe uma annotation que torna o resultado esperado do teste unitário uma exceção. Se o que você espera da execução do teste é uma Exceção, adicione essa annotation no método e serás feliz.

package com.test;

import org.junit.Test;
import java.util.ArrayList;

public class CustomTests {

    @Test(expected = ArithmeticException.class)
    public void testDivisionWithException() {
        int i = 1 / 0;
    }

    @Test(expected = IndexOutOfBoundsException.class)
    public void testEmptyList() {
        new ArrayList<>().get(0);
    }

}

Se isso ainda não lhe ajudar, peço que explique o que se deseja testar, para que eu possa tentar ajudar.

Fico no aguardo,

Abraço,

Rodrigo

Boa tarde, Ivan! Como vai?

Como o Rodrigo disse, para vc fazer um teste ficar esperando o lançamento de uma exceção, vc precisa adicionar a propriedade expected como parâmetro da anotação @Test! Contudo, perceba que seu método em questão em momento nenhum lança uma exceção, então seu teste falharia!

O que vc precisa fazer é lançar a exceção desejada dentro do método que será testado e no método de teste usar o expected como mostrado pelo Rodrigo!

Pegou a ideia? Qualquer coisa é só falar!

Grande abraço e bons estudos, meu aluno!