quarta-feira, 27 de junho de 2012

domingo, 24 de julho de 2011

Testes Unitários e JUnit 4

  • O que são os teste unitários?


O teste unitário ou de unidade é uma modalidade de testes que se concentra na verificação da menor unidade do projeto de software. É realizado o teste de uma unidade lógica, com uso de dados suficientes para se testar apenas a lógica da unidade em questão. Em sistemas construídos com uso de linguagens orientadas a objetos, como Java e C#, essa unidade pode ser identificada como um método, uma classe ou mesmo um objeto.

Um teste unitário deve ser capaz de examinar o comportamento do código sob as mais variadas condições, ou seja, como o código deve se comportar se determinado parâmetro for passado (ou não), o que ele retorna se determinada condição for verdadeira, os efeitos colaterais que ele causa durante a sua execução, se determinada exceção é lançada etc.

Esse tipo de teste é de responsabilidade do próprio desenvolvedor durante a implementação do sistema, isto é, após codificar uma classe, por exemplo, ele planeja, codifica e executa o teste de unidade.


  • JUnit

JUnit é um framework open-source que possibilita a criação de testes unitários em Java. A maioria das IDEs do mercado incorporam o JUnit dentro de seu ambiente de desenvolvimento, facilitando assim o uso desse framework.

O JUnit possibilita a criação das classes de testes. Estas classes contêm um ou mais métodos para que sejam realizados os testes, podendo ser organizados de forma hierárquica, de forma que o sistema seja testado em partes separadas, algumas integradas ou até mesmo todas de uma só vez. Além disso, este framework tem como objetivo, facilitar a criação de casos de teste, além de permitir escrever testes que retenham seu valor ao longo do tempo, ou seja, que possam ser reutilizáveis.

TestCase é a classe que chama os métodos das classes para realizar os testes. Podendo ser realizado um único teste ou vários testes ao mesmo tempo, através do objeto composto TestSuite.

E há as asserções, que tem o objetivo de verificar valores de saída de um processamento, facilitando assim a análise dos resultados obtidos em testes de unidade. Ao executar o JUnit as saídas esperadas são validadas através do métodos chamados assertXxx, onde Xxx pode ser True, False Equals, ou outra condição. Além disso, pode ser passada para esses métodos alguma mensagem especifica caso o teste falhe.


  • Anotações do JUnit

Em sua versão mais atual(JUnit 4.x), o JUnit permite a utilização de anotações para a especificação de casos de teste:

  • @Test. Principal anotação. Indica que o método anotado contém testes.

  • @Before. Identifica método a ser executado antes da execução de todo método de teste. Ou seja, será executado quantas vezes forem o número de métodos de teste (uma vez antes de cada teste). Efeito simétrico à anotação @After.

  • @BeforeClass. Identifica método static que será executado uma única vez por instância da classe que contém os testes e antes da execução de qualquer método de teste. Efeito simétrico ao da anotação @AfterClass.

  • @After. Identifica método para ser executado após cada método de teste, indicado pela anotação @Test. Efeito simétrico à anotação @Before.

  • @AfterClass. Identifica método static para ser executado após a execução de todos os métodos de teste da classe em questão. Ou seja, é executado uma única vez para cada instância da classe de teste, após a execução de todos os métodos de teste.

O .JAR do Junit pode ser encontrado na página principal do próprio framework (http://www.JUnit.org. ).


  • Exemplo:
Criada aqui uma classe ContaCorrente, com suas regras de negócio:
=========================================================================

package com.blogspot.deyvidpinzon.junit;


public class ContaCorrente {

private double saldo;

private double limite;

public ContaCorrente(){

saldo = 50;

limite = 50;

}

public double depositar(double valor) throws Exception{

if(valor < 1){

throw new Exception("Valor Invalido");

}else{

saldo += valor;

}

return saldo;

}

public double sacar(double valor) throws Exception{

if(valor < 1){

throw new Exception("Valor Invalido!");

}

if(!saldoSuficiente(valor)){

throw new Exception("N?o existe saldo Suficiente!");

}else{

saldo -= valor;

}

return saldo;

}

public boolean saldoSuficiente(double valor){

if(saldo+limite > valor)

return true;

return false;

}

public String exibirSaldo(){

return "Saldo: R$"+saldo+

"\nLimite: R$"+limite+

"\nDispon?vel: RS"+(saldo+limite);

}


public double getSaldo() {

return saldo;

}


public void setSaldo(double saldo) {

this.saldo = saldo;

}


public double getLimite() {

return limite;

}


public void setLimite(double limite) {

this.limite = limite;

}

}


=========================================================================

Aqui, criamos nossas classes de teste, crie de preferencia um pacote apenas para os testes.
Vá nesse novo pacote, vá em New > Other... busque por Junit, e selecione como na imagem abaixo:

=========================================================================

package com.blogspot.deyvidpinzon.junitTests;


import static junit.framework.Assert.*;


import org.junit.After;

import org.junit.Before;

import org.junit.Test;


import com.blogspot.deyvidpinzon.junit.ContaCorrente;


public class ContaCorrenteDepositarTest {

ContaCorrente cc;

@Before

public void inicializarCasoDeTeste(){

System.out.println("------ NOVO CASO DE TESTE -------");

cc = new ContaCorrente();

}

@After

public void finalizarCasotDeTeste(){

System.out.println(cc.exibirSaldo());

cc = null;

System.out.println("---------------------------------");

}

//Ao lado da anotação @Test você pode especificar

//um tipo de exceção a ser esperada

@Test(expected=Exception.class)

public void depositarValorIgualZero() throws Exception{

cc.depositar(0);

}

@Test(expected=Exception.class)

public void depositarValorMenorlZero() throws Exception{

cc.depositar(-10);

}

@Test

public void depositarValorValido() throws Exception{

//Primeiro seto o valor do saldo para 100

//após utilizo o "assertEquals" que compara

//o valor esperado com o valor retornado, e

//é possivel adicionar um valor delta, nesse caso 0(zero)

cc.setSaldo(100);

assertEquals(120, cc.depositar(20),0);

}

@Test

public void depositarValorValido2() throws Exception{

//É possí­ovel também utilizar "assertTrue"

//e passar uma condição para ela

//com o valor esperado e o retornado

cc.setSaldo(100);

assertTrue(120 == cc.depositar(20));

}


}

=========================================================================

package com.blogspot.deyvidpinzon.junitTests;


import static junit.framework.Assert.*;


import org.junit.After;

import org.junit.Before;

import org.junit.Test;


import com.blogspot.deyvidpinzon.junit.ContaCorrente;


public class ContaCorrenteSacarTest {

ContaCorrente cc;

@Before

public void inicializarCasoDeTeste(){

System.out.println("------ NOVO CASO DE TESTE -------");

cc = new ContaCorrente();

}

@After

public void finalizarCasotDeTeste(){

System.out.println(cc.exibirSaldo());

cc = null;

System.out.println("---------------------------------");

}

@Test(expected=Exception.class)

public void sacarValorIgualZero() throws Exception{

cc.sacar(0);

}

@Test(expected=Exception.class)

public void sacarValorMenorlZero() throws Exception{

cc.sacar(-10);

}

@Test(expected=Exception.class)

public void sacarValorMaiorQueDisponivel() throws Exception{

cc.setSaldo(20);

cc.sacar(1000);

}

@Test

public void sacarValorValido() throws Exception{

cc.setSaldo(200);

assertEquals(160, cc.sacar(40),0);

}


}

=========================================================================

Se todos seus teste rodarem perfeitamente eles ficarão verdes... assim:


Se ocorrer alguma falha, ficará assim:

Na janela inferior qual foi a falha, nesse caso ele esperava um valor 100.0 e recebeu um valor 160.0:


Se houver um erro, ele ficará assim:

Aqui, foi lançada um exceção inesperada.


Para que você não precise ficar escrevendo "Assert.assert... "em todos os métodos de teste, faça um " import static junit.framework.Assert.*; ", assim só terá de escrever o "assert... "'

Lembre-se disso: “O teste é o primeiro cliente do seu código e o ditado diz que o cliente sempre tem a razão.”