Testes de Unidade com JUnit
-
Upload
elliando-dias -
Category
Technology
-
view
2.740 -
download
0
Transcript of Testes de Unidade com JUnit
Testes de Unidade com JUnit
Introdução prática ao uso de JUnit para desenvolver testes unitários
JUnit
● Junit: framework para desenvolvimento e execução de testes de unidade em programas Java
● Define um modelo de programação para a criação de testes de unidade em classes Java
● Disponibiliza o TestRunner: aplicação em modo texto ou gráfico para execução de testes
● Podemos baixar o Junit em www.junit.org– O arquivo junit.jar deve estar no classpath
do nosso projeto
Facilidades do JUnit
● Permite criação de testes unitários para métodos pertencentes a uma classe
● Permite a definição e execução de um conjunto de testes unitários – Suites de Teste
● Permite a execução de teste com relato de problemas ocorridos e onde especificamente ocorreram os erros
JUnit Passo a Passo
● 1º Passo)– Criar uma classe de teste para cada classe a
ser testada– Exemplo: classe Aritmetica terá como classe
de teste AritmeticaTest– A classe de Teste deve herdar da classe TestCase do framework JUnit
JUnit Passo a Passo
● 2º Passo)– criar métodos de teste para cada método (ou
funcionalidade) a ser testado (cujos nomes devem começar com a palavra “test”) com tipo de retorno void.
– Exemplo para a classe AritmeticaTest:public void testSoma()public void testSubtracao()public void testDivisao()public void testMultiplicacao()
JUnit Passo a Passo
● 3º Passo)– para cada método de teste definir seu
comportamento: – invocação de métodos da classe do sistema a
ser testada– avaliação do resultado dos métodos sendo
testados usando os métodos assertEquals(), fail(), assertNull(), assertNotNull() do framework JUnit
JUnit Passo a Passo
Causa uma falha no teste atual
Compara dois objetos
Compara uma variável com nulo a == nullassertNull(a)
fail()
a != bassertSame(a,b)
a == bassertNotSame(a,b)
a != nullassertNotNull(a)
a == trueassertTrue(a)
a == falseAvalia uma expressão booleana
assertFalse(a)
a.equals(b)Compara dois valores
assertEquals(a,b)
Teste passa seDescriçãoMétodo
Causa uma falha no teste atual
Compara dois objetos
Compara uma variável com nulo a == nullassertNull(a)
fail()
a != bassertSame(a,b)
a == bassertNotSame(a,b)
a != nullassertNotNull(a)
a == trueassertTrue(a)
a == falseAvalia uma expressão booleana
assertFalse(a)
a.equals(b)Compara dois valores
assertEquals(a,b)
Teste passa seDescriçãoMétodo
JUnit Passo a Passo: Exemplo
public class Aritmetica {
public int soma(int op1, int op2) {return op1 + op2;
}
public int subtracao(int op1,int op2) {return op1 -op2;
}
public int multiplicacao(int op1, int op2) {return op1 * op2;
}
public int divisao(int op1, int op2) throws Exception {if (op2 == 0 ) {
throw new Exception("Divisao por zero");} else {
return op1/op2;}
}
}
JUnit Passo a Passo: Exemplo
import junit.framework.*;public class AritmeticaTest extends TestCase {public void testSoma() {
Aritmetica operacoes = new Aritmetica();this.assertEquals(4,operacoes.soma(3,1));
}public void testSubtracao(){
Aritmetica operacoes = new Aritmetica();this.assertEquals(2, operacoes.subtracao(3,1));
}public void testDivisao() {
Aritmetica operacoes = new Aritmetica();try {
operacoes.divisao(3,0);fail("Deveria lançar Excecao");
} catch (Exception e) {}
}public void testMultiplicacao(){
Aritmetica operacoes = new Aritmetica();this.assertEquals(3,operacoes.multiplicacao(3,1));
}}
JUnit Passo a Passo: Exemplo● Como Executar o teste?
– Direto na linha de comando:java junit.textui.TestRunner ContaTeste– Ou inserir os métodos abaixo na classe de teste
public static Test suite(){ return new TestSuite(AritmeticaTest.class);
}
public static void main(String[] args){ junit.textui.TestRunner.run(suite());}
TestRunner chama suite() automaticamente e trata como testes (e executa) todos os métodos sem argumentos cujos nomes começarem com "test"
JUnit Passo a Passo: Exemplo
● Teste com erro
● Teste sem erro
Observações● Caso necessário, pode-se definir configurações iniciais
para serem executadas antes de cada método de teste usando o método setUp()– configuração de objetos comuns aos casos de teste– configuração de recursos comuns aos casos de
teste – (exemplo: abertura de conexões de banco de
dados, socket, etc)● Para liberar recursos utilizados pelos métodos de teste
pode-se usar o método tearDown()– Exemplos de recursos que podem ser liberados:
streams, fechar conexões de banco de dados, apagar/mover arquivos de dados.
JUnit Passo a Passopublic class Aritmetica {
private int op1,op2;
public void setOp1(int op1) {this.op1 = op1;
}
public void setOp2(int op2) {this.op2 = op2;
}public int soma() {
return op1 + op2;}
public int subtracao() {return op1 -op2;
}
public int multiplicacao() {return op1 * op2;
}
public int divisao() throws Exception {if (op2 == 0 ) {
throw new Exception("Divisao por zero");} else {
return op1/op2;}
}
}
JUnit Passo a Passoimport junit.framework.*;
public class AritmeticaTest extends TestCase {
Aritmetica operacoes;
public void setUp() {operacoes = new Aritmetica();operacoes.setOp1(3);operacoes.setOp2(1);
}
public void testSoma() {
this.assertEquals(4,operacoes.soma());
}
public void testSubtracao(){this.assertEquals(2, operacoes.subtracao());
}
public void testDivisao() {try {
this.assertEquals(3,operacoes.divisao());} catch (Exception e) {
}}
public void testMultiplicacao(){this.assertEquals(3,operacoes.multiplicacao());
}}
Executa antes de cada método de teste
Execução JUnit
● Seqüência de execução do JUnit:– Cria uma instância da classe de teste para cada
método de teste. (Exemplo: 4 testes, 4 instâncias).
– O test case é instanciado para executar um método testXXX() de cada vez.
● As alterações que ele fizer ao estado do objeto não afetarão os demais testes
● Para cada instância:– Chama o método setUp();– Chama o método de teste;– Chama o método tearDown();
Suites de Testes
● Quando falamos em teste automatizado, é comum querermos executar um conjunto de testes de uma única vez;
● Suites de testes representam um conjunto de testes que serão executados seqüencialmente;
● JUnit define a classe TestSuite que:– Permite incluir todos os métodos de teste de
uma classe em um suite de teste;– Permite definir uma classe que inclui todos os
suites de teste das classes do sistema.
TestSuite
● Permite executar uma coleção de testes– Método addTest(TestS uite) adiciona um teste na
lista● Padrão de codificação:
– retornar um TestS uite em cada test-case:public static TestSuite suite() {
return new TestSuite(SuaClasseTest.class);}
– criar uma classe AllTests que combina as suites:public class AllTests {
public static Test suite() {TestSuite testSuite = new TestSuite("Roda tudo");
testSuite.addTest(pacote.AllTests.suite());testSuite.addTest(MinhaClasseTest.suite());testSuite.addTest(SuaClasseTest.suite());return testSuite;
} }
Observações gerais
● Cada teste deve verificar um pedaço específico da funcionalidade
● Não combine testes não relacionados em um único método testXXX()
● Se o primeiro teste falhar os seguintes não serão executados
Testes com Objetos Mock
● Mocks– São objetos “de mentira” (substitutos) que
permitem isolar classes de um sistema.
Conta
adicionar(): voidtotal(): int
LinhaItem
total(): int
Conta
adicionar(): voidtotal(): int
Itemnome:Stringpreco: int
Item: Itemquantidade: int
Testes com Objetos Mockpublic class Conta {
private int total;public void adiciona (LinhaItem
linhaItem) {total += linhaItem.total();
}public int total() {
return total;}
}public class LinhaItem {
private Item item;private int quantidade;public LinhaItem(Item item, int quantidade) {
this.item = item;this.quantidade = quantidade;
}public int total() {
return item.getPreco() * quantidade;}
}
public class Item {private String nome;private int preco;
public void setNome(String nome) {this.nome = nome;
}public void setPreco(int preco) {
this.preco = preco;}
}
Testes com Objetos Mockimport junit.framework.TestCase;
public class ContaTeste extends TesteCase {Conta conta = new Conta();Item lasanha = new Item();lasanha.setNome("Lasanha verde");lasanha.setPreco(10);Item refrigerante = new Item();refrigerante.setNome("Guaraná");refrigerante.setPreco(2);Item sorvete = new Item();sorvete.setNome("Sorvete de Chocolate");sorvete.setPreco(4);Item cafe = new Item();cafe.setNome("Cafe Expresso");cafe.setPreco(1);
LinhaItem linhaLasanha = new LinhaItem(lasanha, 2);LinhaItem linhaRefri = new LinhaItem(refrigerante, 4);LinhaItem linhaSorvete = new LinhaItem(sorvete, 1);LinhaItem linhaCafe = new LinhaItem(cafe, 2);
conta.adiciona(linhaLasanha);conta.adiciona(linhaRefri);conta.adiciona(linhaSorvete);conta.adiciona(linhaCafe);
assertEquals(34. conta.total);} }
Testes com Objetos Mock
● Problemas da classe ContaTeste:– Método de teste maior e complexo;– O teste não é verdadeiramente um teste de
unidade:● Uma falha no teste pode ser causada por uma falha
na classe Conta, na classe LinhaItem ou mesmo na classe Item.
● Solução:– Usar objetos mock– Elimina a dependência entre as classes (Conta e
LinhaItem)– Ao testarmos, ao invés de usar a classe
LinhaItem, usaremos uma classe que “finge” ser a ela.
Testes com Objetos Mock
● Como usar mock no exemplo?– Usaremos uma classe especial chamada de
LinhaMock● Essa classe já recebe no construtor o valor total de
uma LinhaItem.– A classe LinhaItem passa a implementar uma
interface, Linha, com um único método: total()– Esse método será utilizado pela classe Conta.
public interface Linha{int total();
}
Testes com Objetos Mock
● Nova classe de Teste:public class ContaTeste{
public void TestaTotalNota() {Conta conta = new Conta();conta.adiciona(new LinhaMock(20));conta.adiciona(new LinhaMock(8));conta.adiciona(new LinhaMock(2));conta.adiciona(new LinhaMock(1));conta.adiciona(new LinhaMock(1));assertEquals(32,conta.total());
}public static Test suite(){
return new TestSuite(ContaTeste.class); }}
Usando Easymock
● Nem sempre é simples escrever objetos mock.
● Ferramenta Easymock: APIs para gerar objetos mock.
● Como fazer para testar um servlet que implementa um mecanismo simplificado de login, recebendo dois parâmetros: login e senha.– Para obter parâmetros em um servlet usamos
● getParameter(“nomeParametro”) da interface HttpServletRequest
Usando Easymock
● Qual seria o problema?– A interface HttpServletRequest possui mais de
10 métodos e só estamos interessados no getParameter().
● Criar um mock objeto para isso significa criar uma classe coma implementação desejada de getParameter() e uma implementação vazia ou mínima para todos os outros métodos.
● Solução:– Usar APIs para gerar e manipular objetos mock.– Ao invés de criarmos uma classe que
implementa uma interface específica, deixamos que o EasyMock faça isso por nós.
● Não precisaremos criar um arquivo para nosso mock.
EasyMock
● O EasyMock pode ser obtido em:– easymock.org
● Basta extrair do download a biblioteca easymock.jar e colocá-la no classpath de seu projeto.
Passo a passo usando EasyMock
● 1º Passo)– Solicitamos a criação de um mock para um
interface particularHttpServletRequest requestMock = createMock(HttpServletRequest.class);
● 2º Passo)– Criamos comportamentos específicos
● O mock objeto request irá esperar que alguma outra classe acesse o seu método getParameter()expect(requestMock.getParameter(“login”)).andReturn(“Marilia”);
expect(requestMock.getParameter(“senha”)).andReturn(“cefet”);
Passo a passo usando EasyMock
● 3º Passo)– Precisamos informar ao mock que ele já não
está mais sendo preparado, ou seja, é hora da ação.
– Para isso usamos o método replay();– A partir deste ponto o mock pode ser usado
normalmente onde antes teria sido necessário utilizar um objeto real da aplicação.
replay(requestMock);LoginServlet loginServlet = new LoginServlet();assertTrue(loginServlet.loginValido(requestMock());
Passo a passo usando EasyMock
● Observações:– Os métodos usados para programar mock ficam
disponíveis para a classe de testes através de um import estático dos métodos da classe EasyMock.
import static org.easymock.EasyMock.*;– É necessário usarmos java 5 ou superior
Passo a passo usando EasyMock
import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletOutputStream out = response.getOutputStream();if(loginValido(request)) {
out.println("Bem-vindo");} else {
out.println("Acesso negado");}
}public boolean loginValido(HttpServletRequest request) {
if("Marilia".equals(request.getParameter("login")) &&"cefet".equals(request.getParameter("senha"))) {
return true;}return false;
}}
Passo a passo usando EasyMock
import javax.servlet.http.HttpServletRequest;import junit.framework.TestCase;import static org.easymock.EasyMock.*;
public class LoginTeste extends TestCase {public void testeLoginComSucesso(){
HttpServletRequest requestMock = createMock(HttpServletRequest.class);expect(requestMock.getParameter("login")).andReturn("Marilia");expect(requestMock.getParameter("senha")).andReturn("cfet");replay(requestMock);
LoginServlet loginServlet = new LoginServlet();assertTrue(loginServlet.loginValido(requestMock));
}
}
Para maiores informações
● Junit:– http://junit.sourceforge.net/
● EasyMock– http://www.easymock.org/EasyMock2_2_Docum
entation.html