33
Testes de Unidade com JUnit Introdução prática ao uso de JUnit para desenvolver testes unitários

Testes de Unidade com JUnit

Embed Size (px)

Citation preview

Page 1: Testes de Unidade com JUnit

Testes de Unidade com JUnit

Introdução prática ao uso de JUnit para desenvolver testes unitários

Page 2: Testes de Unidade com JUnit

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

Page 3: Testes de Unidade com JUnit

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

Page 4: Testes de Unidade com JUnit

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

Page 5: Testes de Unidade com 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()

Page 6: Testes de Unidade com JUnit

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

Page 7: Testes de Unidade com 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

Page 8: Testes de Unidade com JUnit

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;}

}

}

Page 9: Testes de Unidade com JUnit

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));

}}

Page 10: Testes de Unidade com JUnit

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"

Page 11: Testes de Unidade com JUnit

JUnit Passo a Passo: Exemplo

● Teste com erro

● Teste sem erro

Page 12: Testes de Unidade com JUnit

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.

Page 13: Testes de Unidade com JUnit

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;}

}

}

Page 14: Testes de Unidade com JUnit

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

Page 15: Testes de Unidade com JUnit

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();

Page 16: Testes de Unidade com JUnit

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.

Page 17: Testes de Unidade com JUnit

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;

} }

Page 18: Testes de Unidade com JUnit

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

Page 19: Testes de Unidade com JUnit

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

Page 20: Testes de Unidade com JUnit

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;}

}

Page 21: Testes de Unidade com JUnit

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);} }

Page 22: Testes de Unidade com JUnit

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.

Page 23: Testes de Unidade com JUnit

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();

}

Page 24: Testes de Unidade com JUnit

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); }}

Page 25: Testes de Unidade com JUnit

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

Page 26: Testes de Unidade com JUnit

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.

Page 27: Testes de Unidade com JUnit

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.

Page 28: Testes de Unidade com JUnit

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”);

Page 29: Testes de Unidade com JUnit

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());

Page 30: Testes de Unidade com JUnit

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

Page 31: Testes de Unidade com JUnit

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;

}}

Page 32: Testes de Unidade com JUnit

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));

}

}

Page 33: Testes de Unidade com JUnit

Para maiores informações

● Junit:– http://junit.sourceforge.net/

● EasyMock– http://www.easymock.org/EasyMock2_2_Docum

entation.html