O documento fornece uma introdução sobre testes de unidade com JUnit, descrevendo: 1) o que é JUnit e suas funcionalidades; 2) os passos para criar e executar testes de unidade com JUnit; 3) como usar asserções e métodos auxiliares como setUp() e tearDown().
1. Testes de Unidade com JUnit
Introdução prática ao uso de JUnit para
desenvolver testes unitários
2. 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
3. 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
4. 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
5. 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()
6. 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
7. JUnit Passo a Passo
Método Descrição Teste passa se
assertEquals(a,b) Compara dois a.equals(b)
valores
assertFalse(a) a == false
Avalia uma
assertTrue(a) expressão booleana a == true
assertNotNull(a) a != null
Compara uma
assertNull(a) variável com nulo a == null
assertNotSame(a,b) a == b
Compara dois
assertSame(a,b) objetos a != b
fail() Causa uma falha no
teste atual
8. 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(quot;Divisao por zeroquot;);
} else {
return op1/op2;
}
}
}
9. 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(quot;Deveria lançar Excecaoquot;);
} catch (Exception e) {
}
}
public void testMultiplicacao(){
Aritmetica operacoes = new Aritmetica();
this.assertEquals(3,operacoes.multiplicacao(3,1));
}
}
10. 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 quot;testquot;
11. JUnit Passo a Passo: Exemplo
● Teste com erro
● Teste sem erro
12. 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.
13. JUnit Passo a Passo
public 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(quot;Divisao por zeroquot;);
} else {
return op1/op2;
}
}
}
14. JUnit Passo a Passo
import junit.framework.*;
public class AritmeticaTest extends TestCase {
Aritmetica operacoes;
Executa antes de cada
public void setUp() {
operacoes = new Aritmetica();
método de teste
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());
}
}
15. 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();
16. 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.
17. TestSuite
● P ermite executar uma coleção de testes
– Método addTest(TestS uite) adiciona um teste na
lista
● P adrã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(quot;Roda tudoquot;);
testSuite.addTest(pacote.AllTests.suite());
testSuite.addTest(MinhaClasseTest.suite());
testSuite.addTest(SuaClasseTest.suite());
return testSuite;
}
}
18. 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
19. Testes com Objetos Mock
● Mocks
– São objetos “de mentira” (substitutos) que
permitem isolar classes de um sistema.
Conta LinhaItem Item
Item: Item nome:String
quantidade: int preco: int
adicionar(): void
total(): int total(): int
20. Testes com Objetos Mock
public class Conta { public class Item {
private int total; private String nome;
public void adiciona (LinhaItem private int preco;
linhaItem) {
total += linhaItem.total();
public void setNome(String nome) {
}
public int total() { this.nome = nome;
return total; }
} public void setPreco(int preco) {
} this.preco = preco;
}
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;
}
}
21. Testes com Objetos Mock
import junit.framework.TestCase;
public class ContaTeste extends TesteCase {
Conta conta = new Conta();
Item lasanha = new Item();
lasanha.setNome(quot;Lasanha verdequot;);
lasanha.setPreco(10);
Item refrigerante = new Item();
refrigerante.setNome(quot;Guaranáquot;);
refrigerante.setPreco(2);
Item sorvete = new Item();
sorvete.setNome(quot;Sorvete de Chocolatequot;);
sorvete.setPreco(4);
Item cafe = new Item();
cafe.setNome(quot;Cafe Expressoquot;);
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);
} }
22. 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.
23. 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();
}
24. 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);
}
}
25. 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
26. 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.
27. 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.
28. Passo a passo usando
EasyMock
● 1º Passo)
– Solicitamos a criação de um mock para um
interface particular
HttpServletRequest 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”);
29. 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
());
30. 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