Dúvidas JUnit [resolvido]

Boa tarde pessoal.

Estava escrevendo uns testes e me bateu uma dúvida. Para efeito de exemplo, suponham que eu tenha um método assim:

[code]public class Calculadora {
public Calculadora() {
// Faz algo
}

// …

public double dividir(double a, double b) {
if (b == 0) {
throw new ArithmeticException(“Divisão por zero.”);
}

return a / b;

}
}[/code]
Agora suponham que vou escrever uma classe de testes para testar essa calculadora. Eu tenho duas alternativas:

  1. Testar cada possibilidade de erro em um método diferente.

[code]@Test(expected = ArithmeticException.class)
public void testeDivisaoPorZero() {
Calculadora calc = new Calculadora();
calc.dividir(1, 0);
}

@Test
public void testeDivisao() {
Calculadora calc = new Calculadora();
assertTrue(calc.dividir(10, 2), 5);
}[/code]
2) Testar as duas possibilidades em um mesmo método de teste.

@Test(expected = ArithmeticException.class) public void testeDivisao() { Calculadora.calc = new Calculadora(); calc.dividir(1, 0); assertTrue(calc.dividir(10, 2), 5); }

Já que a linha 4 da segunda alternativa disparará uma exceção com toda certeza, a linha 5 será testada?

Abraços

Eu não sei te responder com precisão, mas seria legal você fazer o teste e falar o resultado para nós :wink:

Agora é comum você fazer seus testes separados por métodos, ou seja, cada método na sua classe JUnit deve testar apenas 1 ação. Fica mais fácil para entender o teste, assim como fazer futuras melhorias/refactoring.

Voc só deria ter uma asserção pra cada teste -> http://www.artima.com/weblogs/viewpost.jsp?thread=35578

Realmente… Escrevi esse código no eclipse e coloquei um System.out.println(“Teste”); antes e depois da linha que lança a exceção.

[code]@Test(expected = ArithmeticException.class)
public void testeDivisao() {
Calculadora.calc = new Calculadora();

System.out.println(“Teste”);
calc.dividir(1, 0);
System.out.println(“Teste”);

assertTrue(calc.dividir(10, 2), 5);
}[/code]
A palavra Teste deveria aparecer duas vezes no output. Só apareceu uma.
Fica aí registrado pra galera…

Só isso já tinha me convencido a utilizar a primeira alternativa, descrita em meu post anterior.

Abraços

Obrigado pelo link, Maurício. :wink:

O mais indicado é vc separar por comportamento.

@Test(expected = ArithmeticException.class) public void testeDivisao() { Calculadora.calc = new Calculadora(); calc.dividir(1, 0); assertTrue(calc.dividir(10, 2), 5); }

Vc não vê nada de errado nesse método? Tente usar o EMMA (que faz code coverage) para vc ver que a linha do assertTrue nunca vai ser executada.

Motivo: calc.dividir(1,0) irá lançar uma exception. E uma exception interrompe o bloco de código onde está sendo executada a operação.

Agora, se vc fizesse isso:

@Test(expected = ArithmeticException.class) public void testeDivisao() { Calculadora.calc = new Calculadora(); assertTrue(calc.dividir(10, 2), 5); calc.dividir(1, 0); }

Vc tem 2 comportamentos misturados no seu método de teste. SE por acaso calc.dividir(10, 2) lançar uma exception o teste vai “passar”.

Portanto separe os comportamentos: lançamento de exception e calculos normais.

Sugestão: crie um Setup e um Teardown para os seus testes :wink:

http://junit.sourceforge.net/doc/cookstour/cookstour.htm

Entendi.
De fato, o assert após a chamada ao método que lança a exceção nunca seria executada, conforme confirmei posicionando o System.out.println(“Teste”) em posições estratégicas.

Mas peczenyj, no caso desse exemplo da calculadora, não estou conseguindo enxergar a necessidade de escrever um método setUp(), a não ser que fosse para criar um objeto da classe Calculadora que seria utilizado em todos os métodos de teste. Especificamente nesse exemplo da calculadora, o que você colocaria no setUp()?

Abraços

Saca só:

[code]package br.com.teste;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class CalcTest {
private Calculadora calc;

@Before
public void setUp() throws Exception {
/* cria uma instância novinha de calculadora para cada teste */
calc = new Calculadora();
}

@After
public void tearDown() throws Exception {
/* aqui vc manda ela pro saco ao fim de cada teste */
calc = null;
}

@Test
public void testNormal(){
assertEquals(calc.dividir(4, 2),2);
assertEquals(calc.dividir(-6, 2),-3);
}

@Test(expected=AquelaException.class)
public void testException(){
calc.dividir(3, 0);
}
}[/code]

Talvez nesse contexto não faça sentido mas… imagine q calculadora é mais complexa e tem atributos de instância :wink:

Ahhh, então o setUp() é executado antes de cada teste?
Eu pensava que fosse executada apenas uma vez, como um construtor. Mas se eu fosse mais inteligente, perceberia que não faria sentido criar um método setUp() que faz o mesmo que um construtor :oops: :smiley:

Abraços

Tem um “SetUP” que é executado uma vez só antes de todos os testes, assim como um TearDown

É a anotação @BeforeClass (e tem uma @AfterClass)

Por falar em JUnit, é impressão minha ou no site não tem muita documentação disponível sobre a versão 4.x?