Atenção: esse artigo tem um vídeo complementar. Clique e assista!

De que se trata o artigo:

Este artigo apresenta como podemos criar testes de unidade de uma forma que as dependências entre as classes não sejam um empecilho para a validação da implementação. Através de exemplos práticos, demonstraremos como os Dublês de Teste podem nos ajudar a codificar os testes de uma forma mais simples.

Em que situação o tema é útil:

Esta técnica é útil em situações que precisamos controlar as interações entre os objetos do sistema com a unidade em teste e tornar visível o acoplamento entre as classes.

Resumo DevMan:

Este artigo faz uma breve introdução aos Dublês de Teste e demonstra como aplicar esta técnica utilizando suas variações. Os exemplos foram criados de uma forma que permita ao leitor comparar estas variações e decidir aonde aplicar adequadamente cada uma delas.

Autores: Ismael Soares e Rogério Gomes Rios

Que os projetos de desenvolvimento de software falham ou têm algum tipo de falha, já sabemos. Mas o que poucas pessoas têm conhecimento é que erros, conhecidos como “bugs”, custam muito caro às empresas e a seus clientes. Uma pesquisa feita pela Gartner revela que este custo chega a cerca de 60 bilhões de dólares por ano nos Estados Unidos. A justificativa para tanto prejuízo está no fato de grande parte destas falhas serem resolvidas tardiamente, quando o software já está em produção. A pesquisa informa ainda, que o processo utilizado para o desenvolvimento dos softwares reflete na qualidade final do produto.

De uma forma geral, o processo de desenvolvimento de software pode ser enxergado como uma metodologia ou conjunto de práticas que auxiliam a produção de um software. Essas práticas culminam em um produto que reflete a forma como todo o processo foi conduzido.

Uma prática muito comum em equipes ágeis é utilizar o TDD, ou Desenvolvimento Orientado por Testes, que ganhou tremenda popularidade nos últimos anos. No entanto, o uso desta técnica fica limitado por diversos fatores, tais como: falta de conhecimento do time, arquitetura mal elaborada, código legado e, principalmente, dependências internas e externas (outras classes, serviços, banco de dados, etc.).

Com base nisso, neste artigo apresentaremos algumas formas de resolver facilmente o problema com as dependências utilizando Dublês de Teste, que simulam o comportamento de objetos reais de forma controlada.

Dublês de Testes

Quando a indústria do cinema quer filmar algo que exige um nível mais especializado de formação e/ou capacidade física para o ator principal, eles contratam um “dublê” para tomar o lugar na cena. O dublê é um indivíduo altamente treinado, capaz de atender aos requisitos específicos da cena. Eles podem não ser capazes de interpretar tão bem quanto o ator principal, mas sabem como cair de grandes alturas, simular cenas de grande perigo, ou o que quer que seja necessário. Como de perto o dublê precisa se parecer com o ator, os diretores escolhem alguém que o lembre vagamente em altura e peso. A mesma necessidade ocorre no desenvolvimento de software. Quando não se pode usar o objeto real ao escrever o teste, usa-se um dublê.

O termo Dublês de Teste foi sugerido por Gerard Meszaros, quando trabalhava em seu livro xUnit Test Patterns (xunitpatterns.com), como um nome genérico para os objetos usados na substituição de objetos reais.

Isolamento do Comportamento

Em um software, as classes dificilmente funcionam isoladamente e frequentemente se comunicam com outros elementos da aplicação. Quando construímos umteste de unidade, um dos principais desafios é exatamente isolar a classe que está sendo testada para garantir o seu comportamento.

Do ponto de vista de teste de unidade, considera-se comportamento a ação esperada ou realizada por um método de uma classe. Para garantir a eficiência deste comportamento é preciso observá-lo de maneira isolada, ou seja, garantir que objetos externos não alterarão o resultado. Para que isto seja possível, estas influências devem de alguma forma ser controladas. Quando não se tem este controle e ocorre um erro durante a execução de um teste, torna-se difícil saber ao certo se a causa está na unidade em teste ou nos objetos relacionados.

Tipos de Dependências

Considera-se dependência, um objeto do sistema que a unidade em teste interage e sobre o qual não possui controle. Por exemplo: uma classe, um serviço, um banco de dados, etc.

As dependências podem ser de dois tipos: entradas e saídas indiretas. As entradas indiretas são dados que a unidade de teste obtém de algum objeto do qual ela depende. Veja um exemplo deste tipo de dependência na Listagem 1. Este código trata da emissão de uma nota fiscal, e neste caso, faz-se necessário gravar o usuário que efetuou a operação de faturar. No entanto, em sistemas que exigem o controle de acesso, é comum ter um serviço que disponibiliza as informações do usuário (linha 9). Desta forma, pode-se afirmar que o método faturar() depende deste serviço (seguranca), ou seja, de uma entrada indireta.

Observando ainda a Listagem 1, note que logo após o faturamento da nota fiscal ocorre a geração do movimento do estoque (linha 3). Esta operação é realizada pelo serviço estoqueService (linha 14), porém, apenas através do objeto que é retornado (fatura linha 4), não é possível garantir que o estoque foi movimentado. Este tipo de efeito colateral é chamado de saída indireta.

Listagem 1. Exemplo de tipos de dependências.


  1.  public Fatura faturar(final NotaFiscal notaFiscal) {
  2.    final Fatura fatura = criarFatura(notaFiscal);
  3.    this.geraMovimentoDoEstoque(notaFiscal);
  4.    return fatura;
  5.  }
   
  6.  private Fatura criarFatura(final NotaFiscal notaFiscal) {
  7.    Fatura fatura = new Fatura();
  8.    fatura.setNotaFiscal(notaFiscal);
  9.    fatura.setFaturista(seguranca.getUsuario());
  10.   faturaDao.salvar(fatura);
   
  11.   return fatura;
  12. }
   
  13. private void geraMovimentoDoEstoque(NotaFiscal notaFiscal) {
  14.   estoqueService.gerarMovimentoAPartirDa(notaFiscal);
  15. } ... 

Quer ler esse conteúdo completo? Tenha acesso completo