Palestra Café com Tapioca:
      Testes de Unidade com Junit




Instrutor: Fabrício Lemos           15/12/2007
Agenda
●   Conceito de Testes de Unidade
●   Junit
●   EasyMock
●   DbUnit
●   Desenvolvimento Guiado por Testes - TDD
Testes de Software
●   É um tópico importante e vital no
    desenvolvimento de software
●   Todo mundo sabe que testes pr...
Testes de Software
●   O sistema deve passar por diversos tipos de teste
    antes de entrar em produção
    –   Unidade
 ...
Testes de Software
●   É praticamente impossível evitar que erros sejam
    inseridos no código
    –   Atividade complexa...
Testes de Software
●   Mesmo tendo reconhecida importância no
    desenvolvimento de software, os teste costumam
    ser v...
Testes de Software
●   Muitos projetos assumem que o código
    desenvolvido está livre de erros e postergam os
    testes...
Testando o Código da Aplicação
●   Como ter certeza de que o código escrito faz o
    que deveria fazer e não contém erros...
Testando o Código da Aplicação
●   Testes não são automatizados
    –   Não é possível utiliza-los na integração contínua
...
Testes de Unidade
●   Examinam o comportamento de uma “unidade de
    trabalho” distinta
    –   Em java, geralmente repre...
Objetivos
●   Verificar se um pedaço de código faz o que o
    desenvolvedor acha que ele faz
●   Verificar se um pedaço d...
Vantagens dos Testes de Unidade
●   Permite uma grande cobertura dos testes
●   Pode facilmente simular condições de erro
...
Vantagens
●   Diminui o tempo gasto com depuração de código
    ●   Quando há algum erro, te diz o método que falhou e o
 ...
Vantagens
●   São facilmente incorporados na Integração
    Contínua
●   Relatórios sobre a corretude do código e a
    co...
Junit
●   Framework de teste criado por Erich Gamma e
    Kent Beck
●   Possui uma api bastante fácil e simples
●   Rapida...
Junit
●   Foram desenvolvidas diversas extensões para
    facilitar os testes de partes específicas de um
    projeto
    ...
Escrevendo os Testes

public class Calculadora {

    public int somar(int op1, int op2) {
      return op1 + op2;
    }

}
Escrevendo os Testes
import static org.junit.Assert.*;
import org.junit.Test;

public class TestCalculadora {

    @Test
 ...
Se o método passar no teste...
Se o método não passar no teste...
Outros Asserts
void assertEquals(Object expected, Object actual)

void assertTrue(boolean condition)

void assertFalse(boo...
Boas Práticas
●   Cada classe do sistema deve ter sua própria classe
    testadora
●   Cada método do sistema deve ter seu...
Boas Práticas
●   Pacote da classe testadora deve ser o mesmo da
    classe testada
    –   Permite o teste de métodos pro...
Classe Usuario

public class Usuario {

    private String nome;

    private Integer idade;

    //get e set...

}
Validação de um Usuário

public boolean validarUsuario(Usuario usr) {

if (usr.getIdade() > 0 &&
       usr.getNome().leng...
Testando a Validação
@Test
public void testValidarUsuario() {

    Usuario usuario = new Usuario();
    usuario.setIdade(1...
Testando a Validação
@Test
public void testValidarInvalido() {

    Usuario usuario = new Usuario();
    usuario.setIdade(...
Isolando os Métodos Testados
●   A maioria dos métodos de um sistema possui
    dependências externas à classe
●   Umas da...
Método com Dependência

public void inserirUsuario(Usuario usuario) {

    usuario.setDataCadastro(new Date());

    if(va...
Objetos Mock
●   Na realização dos testes (em tempo de execução),
    as dependências são substituídas por objetos
    Moc...
EasyMock
●   Biblioteca para geração dinâmica de Mocks
●   Gera objetos mock que implementam qualquer
    interface da apl...
EasyMock
●   Permite verificar se o método testado colaborou
    corretamente com a dependência
    –   Permite a configur...
Utilizando Mocks
1.Criar o mock da interface a ser simulada
2.Configurar o comportamento do mock
3.Fazer com que a unidade...
Utilizando Mocks


// 1. criando o mock
UsuarioDAO mock =
  EasyMock.createMock(UsuarioDAO.class);
Utilizando Mocks

// 2. configurando o comportamento do
// mock
Usuario usuario = new Usuario();
usuario.setIdade(25);
usu...
Utilizando Mocks

// 3. Injetando o Mock
UsuarioManager manager =
  new UsuarioManager();

manager.setUsuarioDAO(mock);

/...
Utilizando Mocks

// 5. Verificando o comportamento do
// método
assertNotNull(usuario.getDataCadastro());

// 6. Verifica...
Mocks – Boas Práticas
●   Sempre utilize injeção de dependências em suas
    classes
●   Acesse as dependências através de...
Testando a Camada de Persistência
●   Como ter certeza de que seu código de acesso a
    dados está lendo e escrevendo cor...
Testando a Camada de Persistência
●   Para automatizar os testes duas condições tem
    que ser satisfeitas
    –   O cont...
DbUnit
●   Extensão do Junit especializada em testes
    integrados ao banco de dados
●   Permite o controle do conteúdo a...
Testando com o DbUnit
  ●   O conteúdo da base de dados é configurado
      através de DataSet no formato XML
  ●   Por de...
Testando com o DbUnit
●   Classe de teste deve herdar de DatabaseTestCase
●   Implementar os métodos
    –   IDatabaseConn...
Testando com o DbUnit
protected IDatabaseConnection getConnection()
  throws ClassNotFoundException,
         SQLException...
Testando com o DbUnit

protected IDataSet getDataSet() throws
  DataSetException, IOException {

    FileInputStream fileI...
Testando a Seleção de Usuários

public interface UsuarioDAO {

    List<Usuario> selecionarUsuarios(
      String  nome);
...
Realizando o Teste
●   Montar o(s) parâmetro(s) para a busca
●   Criar o retorno esperado de acordo com o
    DataSet de p...
@Test
public void testSelecionarUsuarios() {

    String parametroBusca = "jose";

    List<Usuario> esperado = new
      ...
Desenvolvimento Guiado por Testes
            (TDD)
●   A escrita de testes ajuda na melhoria do design do
    código
●   ...
TDD
●   Quanto mais cedo os testes são implementados,
    maiores são os benefícios
    –   Evita que bugs se espalhem pel...
TDD
●   A regra básica do TDD é somente escrever
    código se existir algum teste falhando
    –   Regra válida para impl...
Codificando com TDD
●   Escreva o teste para a funcionalidade desejada
    –   O teste irá falhar
●   Escreva o código nec...
Vantagens do TDD
●   Antes mesmo de começar a implementar o
    método, o desenvolvedor já tem definido qual
    será seu ...
Vantagens do TDD
●   Mantém o desenvolvedor focado no problema a
    ser resolvido
    –   Código é o mais simples que fun...
Duvidas???
          ●   Contato
    –fabricio.lemos@gmail.com
–   discussao@cejug.dev.java.net
Referências
●   http://www.junit.org/
●   http://www.easymock.org/
●   http://dbunit.sourceforge.net/
●   JUnit in Action
...
Testes de Unidade com Junit
Testes de Unidade com Junit
Próximos SlideShares
Carregando em…5
×

Testes de Unidade com Junit

5.078 visualizações

Publicada em

Palestra ministrada por Fabricio Lemos no Cafe Com Tapioca do CEJUG com o tema
"Testes de Unidade com Junit"

Publicada em: Tecnologia
0 comentários
1 gostou
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
5.078
No SlideShare
0
A partir de incorporações
0
Número de incorporações
19
Ações
Compartilhamentos
0
Downloads
138
Comentários
0
Gostaram
1
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Testes de Unidade com Junit

  1. 1. Palestra Café com Tapioca: Testes de Unidade com Junit Instrutor: Fabrício Lemos 15/12/2007
  2. 2. Agenda ● Conceito de Testes de Unidade ● Junit ● EasyMock ● DbUnit ● Desenvolvimento Guiado por Testes - TDD
  3. 3. Testes de Software ● É um tópico importante e vital no desenvolvimento de software ● Todo mundo sabe que testes precisam ser feitos ● Existe uma quantidade enorme de aspectos que precisam ser testados em um sistema
  4. 4. Testes de Software ● O sistema deve passar por diversos tipos de teste antes de entrar em produção – Unidade – Integração – Funcional – Stress e performance – Aceitação
  5. 5. Testes de Software ● É praticamente impossível evitar que erros sejam inseridos no código – Atividade complexa – Manipula uma grande quantidade de elementos abstratos – Inclusões de novas funcionalidades podem influenciar nas já existentes – Muitas vezes é difícil ter certeza que o código está totalmente correto até que ele seja executado – Geralmente os desenvolvedores do projeto possuem diferentes níveis de habilidades
  6. 6. Testes de Software ● Mesmo tendo reconhecida importância no desenvolvimento de software, os teste costumam ser vistos como uma atividade chata e repetitiva – Só costumam receber atenção quando os problemas começam a ser tornar comuns ● Geralmente só são iniciados quando o produto está todo “pronto”
  7. 7. Testes de Software ● Muitos projetos assumem que o código desenvolvido está livre de erros e postergam os testes para as fases finais do desenvolvimento – Preferem remediar do que prevenir – “Está tudo pronto, só falta testar”
  8. 8. Testando o Código da Aplicação ● Como ter certeza de que o código escrito faz o que deveria fazer e não contém erros? ● Abordagens comumente usadas – Escreve-se um método main que chama o método escrito e verifica-se o retorno – Espera-se que a funcionalidade esteja pronta e realiza- se um teste funcional manual ● Os testes são feitos de maneira pontual – Não é possível a realização de testes de regressão
  9. 9. Testando o Código da Aplicação ● Testes não são automatizados – Não é possível utiliza-los na integração contínua ● Não são gerados relatórios sobre a execução dos testes ● Testes não são executados de maneira isolada – Maior dificuldade em encontrar a fonte de um erro ● Não há disciplina para a realização dos testes
  10. 10. Testes de Unidade ● Examinam o comportamento de uma “unidade de trabalho” distinta – Em java, geralmente representada por um único método ● Unidades de trabalho são testadas de maneira isolada ● Possuem natureza diferente dos testes de integração e de aceitação – examinam como vários componentes interagem
  11. 11. Objetivos ● Verificar se um pedaço de código faz o que o desenvolvedor acha que ele faz ● Verificar se um pedaço de código SEMPRE faz o que o desenvolvedor acha que ele faz ● Identificar bugs prematuramente ● Permitir que novas funcionalidades sejam adicionadas sem comprometer as já existentes ● Diminuir o impacto das refatorações de código
  12. 12. Vantagens dos Testes de Unidade ● Permite uma grande cobertura dos testes ● Pode facilmente simular condições de erro ● Melhora o trabalho em equipe ● Permite ao desenvolvedor entregar código de qualidade (testado) sem esperar que outras partes estejam prontas ● Dá-lhe a confiança que seu código funciona ● “Alguém” assistindo a alteração/inclusão de novas funcionalidades
  13. 13. Vantagens ● Diminui o tempo gasto com depuração de código ● Quando há algum erro, te diz o método que falhou e o motivo da falha ● Melhora a implementação ● Testes de unidade são os primeiros “clientes” do código ● Serve como uma documentação do código ● Aprendizagem por exemplos
  14. 14. Vantagens ● São facilmente incorporados na Integração Contínua ● Relatórios sobre a corretude do código e a cobertura dos testes são gerados de maneira automática
  15. 15. Junit ● Framework de teste criado por Erich Gamma e Kent Beck ● Possui uma api bastante fácil e simples ● Rapidamente se tornou o framework padrão para testes em Java ● Possui suporte para diversas ferramentas: Eclipse, Maven, Ant, etc....
  16. 16. Junit ● Foram desenvolvidas diversas extensões para facilitar os testes de partes específicas de um projeto – EasyMock – DbUnit – StrutsTestCase – Cactus – Shale Test Framework – etc...
  17. 17. Escrevendo os Testes public class Calculadora { public int somar(int op1, int op2) { return op1 + op2; } }
  18. 18. Escrevendo os Testes import static org.junit.Assert.*; import org.junit.Test; public class TestCalculadora { @Test public void testSomar() { Calculadora calc = new Calculadora(); int resultado = calc.somar(2, 3); assertEquals(5, resultado); } }
  19. 19. Se o método passar no teste...
  20. 20. Se o método não passar no teste...
  21. 21. Outros Asserts void assertEquals(Object expected, Object actual) void assertTrue(boolean condition) void assertFalse(boolean condition) void fail() void assertArrayEquals(Object[] expecteds, Object[] actuals) void assertNull(Object object) void assertNotNull(Object object) void assertEquals(String message, Object expected, Object actual)
  22. 22. Boas Práticas ● Cada classe do sistema deve ter sua própria classe testadora ● Cada método do sistema deve ter seu próprio método testador ● O nome das classes testadoras devem seguir o padrão TestNomeClasseTestada – Não prejudica o code completion – Classes reconhecidas automaticamente pelo Maven
  23. 23. Boas Práticas ● Pacote da classe testadora deve ser o mesmo da classe testada – Permite o teste de métodos protected ● Classes testadoras devem ser armazenadas em pastas separadas – Facilita o empacotamento da aplicação – src/test/java ● Padrão do Maven
  24. 24. Classe Usuario public class Usuario { private String nome; private Integer idade; //get e set... }
  25. 25. Validação de um Usuário public boolean validarUsuario(Usuario usr) { if (usr.getIdade() > 0 && usr.getNome().length() > 2) { return true; } return false; }
  26. 26. Testando a Validação @Test public void testValidarUsuario() { Usuario usuario = new Usuario(); usuario.setIdade(18); usuario.setNome("Cejug"); boolean resultado = new UsuarioManager().validarUsuario(usuario); assertTrue(resultado); }
  27. 27. Testando a Validação @Test public void testValidarInvalido() { Usuario usuario = new Usuario(); usuario.setIdade(18); usuario.setNome(""); boolean resultado = new UsuarioManager().validarUsuario(usuario); assertFalse(resultado); }
  28. 28. Isolando os Métodos Testados ● A maioria dos métodos de um sistema possui dependências externas à classe ● Umas das principais características dos testes de unidade é o isolamento das unidades testadas – Permite facilmente identificar o local do erro ● Diminui o tempo de debug – As dependências não precisam estar prontas para que o método seja testado ● Para isolar os métodos testados, as dependências devem ser substituídas por dependências “falsas”
  29. 29. Método com Dependência public void inserirUsuario(Usuario usuario) { usuario.setDataCadastro(new Date()); if(validarUsuario(usuario)){ usuarioDAO.inserirUsuario(usuario); } else { throw new IllegalArgumentException(); } }
  30. 30. Objetos Mock ● Na realização dos testes (em tempo de execução), as dependências são substituídas por objetos Mock – Injeção de dependência ● Simulam as dependências dos métodos testados ● São objetos “vazios” – Não contém nenhuma lógica ● Podem ser feitos pelo próprio desenvolvedor ou a partir de alguma biblioteca
  31. 31. EasyMock ● Biblioteca para geração dinâmica de Mocks ● Gera objetos mock que implementam qualquer interface da aplicação – Possui uma extensão para geração de mocks para classes
  32. 32. EasyMock ● Permite verificar se o método testado colaborou corretamente com a dependência – Permite a configuração dos objetos mock ● Quais os argumentos que o mock deve receber do método testado ● Qual deve ser o retorno do método chamado ● Se a chamada deve lançar alguma exceção ● Facilidade para simular condições de erro
  33. 33. Utilizando Mocks 1.Criar o mock da interface a ser simulada 2.Configurar o comportamento do mock 3.Fazer com que a unidade testada utilize o objeto mock ao invés da dependência original 1.Injetar o Mock 4.Chamar a unidade a ser testada 5.Verificar o valor retornado 6.Verificar se a unidade testada colaborou corretamente com o mock
  34. 34. Utilizando Mocks // 1. criando o mock UsuarioDAO mock = EasyMock.createMock(UsuarioDAO.class);
  35. 35. Utilizando Mocks // 2. configurando o comportamento do // mock Usuario usuario = new Usuario(); usuario.setIdade(25); usuario.setNome("Café com Tapioca"); mock.inserirUsuario(usuario); EasyMock.replay(mock);
  36. 36. Utilizando Mocks // 3. Injetando o Mock UsuarioManager manager = new UsuarioManager(); manager.setUsuarioDAO(mock); // 4. chamando o método a ser // testado manager.inserirUsuario(usuario);
  37. 37. Utilizando Mocks // 5. Verificando o comportamento do // método assertNotNull(usuario.getDataCadastro()); // 6. Verificando se o método // usuarioDao.inserir() foi chamado com o // usuário passado EasyMock.verify(mock);
  38. 38. Mocks – Boas Práticas ● Sempre utilize injeção de dependências em suas classes ● Acesse as dependências através de suas Interfaces e não através da implementação ● Tenha bem definido qual o comportamento de seus métodos nas interações com as dependências
  39. 39. Testando a Camada de Persistência ● Como ter certeza de que seu código de acesso a dados está lendo e escrevendo corretamente na base de dados? ● É necessária uma integração com o banco de dados na realização dos testes – Misto entre teste de unidade e teste de integração ● Quando feita de forma não automática, a verificação depende da inspeção visual do conteúdo da base de dados
  40. 40. Testando a Camada de Persistência ● Para automatizar os testes duas condições tem que ser satisfeitas – O conteúdo da base de dados tem ser conhecido no início de cada teste – Deve ser possível verificar o conteúdo da base de dados após cada teste ● Os testes ainda devem ser realizados independentemente – Testar a inserção independentemente da seleção
  41. 41. DbUnit ● Extensão do Junit especializada em testes integrados ao banco de dados ● Permite o controle do conteúdo armazenado na base de dados – Exporta dados para a base através de arquivos XML ● Possui métodos de verificação do estado da base de dados – Importa dados da base e compara com arquivos XML
  42. 42. Testando com o DbUnit ● O conteúdo da base de dados é configurado através de DataSet no formato XML ● Por default, antes de cada teste a base de dados é esvaziada e re-populada com o conteúdo do DataSet <dataset> <Usuario codigo="-1" nome="josefino" idade="20" /> <Usuario codigo="-2" nome="maria" idade="40" /> <Usuario codigo="-3" nome="jose" idade="40" /> </dataset>
  43. 43. Testando com o DbUnit ● Classe de teste deve herdar de DatabaseTestCase ● Implementar os métodos – IDatabaseConnection getConnection() ● Retorna uma conexão com a base de dados – IDataSet getDataSet() ● Retorna o DataSet para o povoamento da base de dados
  44. 44. Testando com o DbUnit protected IDatabaseConnection getConnection() throws ClassNotFoundException, SQLException { Class.forName("org.hsqldb.jdbcDriver"); Connection jdbcConnection = DriverManager.getConnection( "jdbc:hsqldb:sample", "sa", ""); return new DatabaseConnection(jdbcConnection); }
  45. 45. Testando com o DbUnit protected IDataSet getDataSet() throws DataSetException, IOException { FileInputStream fileIS = new FileInputStream("dataset.xml"); return new FlatXmlDataSet(fileIS); }
  46. 46. Testando a Seleção de Usuários public interface UsuarioDAO { List<Usuario> selecionarUsuarios( String nome); }
  47. 47. Realizando o Teste ● Montar o(s) parâmetro(s) para a busca ● Criar o retorno esperado de acordo com o DataSet de povoamento da base de dados ● Realizar a busca ● Verificar se o resultado da busca é igual ao resultado esperado
  48. 48. @Test public void testSelecionarUsuarios() { String parametroBusca = "jose"; List<Usuario> esperado = new ArrayList<Usuario>(); esperado.add(new Usuario(-3L)); esperado.add(new Usuario(-1L)); List<Usuario> retorno usuarioDAO. selecionarUsuarios(parametroBusca); assertEquals(esperado, retorno); }
  49. 49. Desenvolvimento Guiado por Testes (TDD) ● A escrita de testes ajuda na melhoria do design do código ● Ao se perceber os benefícios dos testes, a tendência é escreve-los o quanto antes ● Com o alcance da maturidade, durante a implementação de um método o desenvolvedor já imagina como irá testa-lo
  50. 50. TDD ● Quanto mais cedo os testes são implementados, maiores são os benefícios – Evita que bugs se espalhem pela aplicação e os tornam mais fáceis de ser corrigidos ● Os adeptos do TDD levam essa prática ao estremo – Os testes são escritos antes do código a ser testado
  51. 51. TDD ● A regra básica do TDD é somente escrever código se existir algum teste falhando – Regra válida para implementação de novas funcionalidades ou para correção de bugs ● Somente o código estritamente necessário para fazer o teste passar deve ser escrito – Refatorações são permitidas
  52. 52. Codificando com TDD ● Escreva o teste para a funcionalidade desejada – O teste irá falhar ● Escreva o código necessário e suficiente para o teste passar ● Refatore o código – Elimine possíveis duplicações de código ● Repita os passos quantas vezes necessário ● Entregue o código
  53. 53. Vantagens do TDD ● Antes mesmo de começar a implementar o método, o desenvolvedor já tem definido qual será seu comportamento ● O código já nasce sem vícios de design ● Evita que bugs sejam adicionados ao código
  54. 54. Vantagens do TDD ● Mantém o desenvolvedor focado no problema a ser resolvido – Código é o mais simples que funciona ● Não procura antecipar mudanças – Manutenção é garantida pela não duplicidade e pela simplicidade do código
  55. 55. Duvidas??? ● Contato –fabricio.lemos@gmail.com – discussao@cejug.dev.java.net
  56. 56. Referências ● http://www.junit.org/ ● http://www.easymock.org/ ● http://dbunit.sourceforge.net/ ● JUnit in Action – Vincent Massol ● JUnit Recipes: Practical Methods for Programmer Testing – J. B. Rainsberger ● Extreme Programming – Vinicius Manhaes Teles

×