Tag Archives: testes de unidade

Testes e infraestrutura: inimigos de longa data

TL;DR: Suas classes com regras de negócio não podem depender de infraestrutura. Elas devem ser facilmente testáveis por meio de testes de unidade. Dependências devem ter interfaces amigáveis e serem facilmente mockadas.

Às vezes ouço perguntas como “como testo meu sistema em Android”, ou “como testo meu sistema em JSF”, ou “como testo meu sistema em <ponha-sua-tecnologia-aqui>”. Pra mim, essa pergunta faz todo sentido se você está procurando uma maneira de fazer testes de sistema. Algo como Selenium, só que Android. No entanto, se você está pensando em testes de unidade, essa pergunta não deveria ser muito importante.

Regras de negócio são importantes. Tão importantes que merecem ficar o mais afastado possível da sua infraestrutura. Ou seja, não importa se você usa JSF, Android, ou whatever, o coração do sistema deve ficar em classes Java, simples, que não dependem de nada externo. Se você pensar sempre assim, pronto, todas suas regras de negócio serão facilmente testadas.

Ah, mas e se pra realizar aquela regra de negócios, eu precisar consultar uma infraestrutura? Sei lá, pegar um dado do banco de dados, ou postar algo em um serviço web? Faça sua classe depender de uma classe que tenha uma interface bastante amigável. Algo como bd.pegaValor() ou correios.calcula(“SP”). Nada que você tenha que ficar escrevendo linhas e linhas para chegar no resultado que espera. Assim, fica fácil mockar depois para testar. E dentro da dependência, você faz o que tiver que fazer pra fazer a infraestrutura funcionar.

Se você pensar assim sempre, a infraestrutura que está usando deixa de ser importante. Afinal, você fugiu dela. E testou o que precisava ser testado.

Não teste fluxos!

Recebi esses dias um e-mail bastante interessante. A pergunta era: devo ou não devo testar o código abaixo?

A pergunta é bastante válida, afinal podemos pensar em dois caminhos diferentes para testar esse código:

  • Fazer um teste de integração, batendo no banco de dados de verdade. Assim, garantiríamos que o salva() realmente funciona.
  • Fazer um teste de unidade, mockar o DAO, e garantir que a regra de validação funciona, e que o salva() é invocado.

A minha abordagem seria: não teste!

Quando o código basicamente controla fluxo, eu evito testá-lo com testes de unidade. Simplesmente não faz sentido. Você vai ficar apanhando com mocks, e no fim, vai só garantir que os métodos são invocados na ordem certa.

Nesse código em particular, eu preferia mover a função valida() para uma classe separada, e testá-la isoladamente. O DAO também teria um teste para o salvar(). E o código acima, que apenas controla o fluxo não teria testes de unidade.

Mas como eu o testaria? Se for uma aplicação web, esse código provavelmente estaria em um controlador. Aí, eu prefiro testar via teste de sistema. Aliás, o argumento que dei aqui é o mesmo que dou para quando digo que também não testo controladores de maneira isolada.

Primeiros Passos com Testes de Unidade – Parte 3

No post anterior, discutimos um pouco sobre pensar nos vários cenários. E conseguimos! Agora que nossa bateria de testes está legal, perceba a segurança que ela nos dá. Podemos abrir o método joga() e mudar sua implementação inteira. Para garantir que ela funciona, basta rodarmos os testes. Veja como eles nos dão a liberdade de mexermos no código à vontade, sem medo. Isso é um grande benefício da nossa bateria de testes.

O próximo passo é começar a pensar na qualidade do código que escrevemos em nossos testes. Afinal, você já percebeu que escreveremos muito código. E, claro, se ele não for fácil de manter, teremos problemas.

Nesse post, vamos começar devagar. Vamos remover o código repetido que existe em todos os nossos testes. Repare que a linha abaixo está em todos nossos testes:

Além de repetida, essa é uma linha perigosa em nossos testes. Ela é a linha que instancia a classe sob teste. Isso significa que qualquer mudança em seu projeto pode fazer com que a bateria de testes inteira pare de funcionar. Faça um teste e modifique o construtor dela! Mais pra frente, mostrarei que, ao projetar para testabilidade, construtores são fundamentais e mudam com frequência.

Vamos então isolar essa linha em um método só pra ele. Esse método instancia o objeto e o guarda em um atributo da classe, para que consigamos vê-lo dentro de qualquer dos métodos de teste:

Agora podemos remover a linha repetida de todos nossos métodos de teste. E como esse é um método que queremos executar antes de cada método de teste, basta avisarmos ao JUnit para fazer isso automaticamente. E só anotar o método de setUp() com @Before. Veja como ficou todo nosso código:

Você pode colocar um Sysout dentro do setUp() para perceber que ele é executado sempre antes de cada teste. E veja que agora se mudarmos o construtor dessa classe, mudaremos apenas em um lugar. Muito melhor e contrado.

Por esse post, é isso. Lembre-se então de evitar código repetido nos seus testes e, em particular, o código que instancia a classe sob teste.

Primeiros Passos com Testes de Unidade – Parte 2

No post passado, escrevemos testes para o FizzBuzz. E foi fácil: criamos a classe FizzBuzzTest e escrevemos lá métodos, com diferentes entradas e saídas. A grande charada é que, como conhecemos a entrada, também sabemos a saída. Mas será que os testes que temos são suficientes? Vamos agora discutir um pouco sobre o que testar.

Veja novamente nosso código de produção:

O grande truque é olhar para o código e pensar nos vários caminhos diferentes que ele pode ter. Para isso, analisarmos cada instrução que faz o fluxo do código mudar. Por exemplo, ifs, fors, whiles, etc. Em nosso FizzBuzz, temos:

  • Cenário 1: O primeiro if tem duas condições: número é múltiplo de 5 E múltiplo de 7. Se esse if der verdadeiro, o programa retorna “fizzbuzz” e acaba.
  • Cenário 2: O segundo if valida se o número é múltiplo de 5. Se der verdadeiro, o programa retorna “fizz” e acaba.
  • Cenário 3: O terceiro if valida se o número é múltiplo de 7. Se der verdadeiro, o programa retorna “buzz” e acaba.
  • Cenário 4: O quarto caminho acontece quando nenhum dos anteriores acontece. O programa retorna o número e acaba.

O próximo passo é: qual a entrada que precisamos passar para que o cenário 1 aconteça? E depois, para o cenário 2? E assim por diante. Foi o que fizemos: passamos 35 para o cenário 1 acontecer, ou 13 para o cenário 4 acontecer.

E perceba também que temos um teste para cada cenário. Preciso de mais? Geralmente não. Se você pensar bem nos cenários, verá que não precisará exercitar mais de uma entrada em cada. Chamamos essas entradas diferentes, mas que exercitam o código da mesma maneira, de classes de equivalência. Um teste por classe de equivalência é uma boa regra a seguir.

No entanto, nada te impede de ter um pouco mais de segurança. Quando lidamos com algoritmos que envolvem números, como é o caso desse, podemos exercitar cenários similares. Não só para garantir que funciona, mas também para facilitar o entendimento quando outro desenvolvedor ler o teste.

E casos excepcionais? Se você achar que seu programa precisa tratar casos excepcionais, como zero, nulo ou exceção, você então deve escrever o teste para garantir que seu programa se comportará corretamente.

Neste post, discuti sobre como deve ser seu pensamento na hora de escrever um teste. Mas ainda temos 3 posts. Estamos chegando lá! 🙂

Primeiros Passos com Testes de Unidade – Parte 1

Olá,

Para comemorar os 50 posts do meu blog, farei uma série sobre primeiros passos com testes de unidade. Então, se ainda não pratica, essa é a hora!

Bem, pra testar código, significa que precisamos ter código, certo? Então, veja o exemplo abaixo. É uma simples implementação do jogo fizzbuzz. Se o número é múltiplo de 5, ele imprime “fizz”. Se é múltipo de 7, ele imprime “buzz”. Se é múltplo de 5 e 7, imprime “fizzbuzz”. Caso contrário, só imprime o número.

A pergunta é: como testar esse código de maneira automática? Será que existe algum robôzinho mágico que sai por aí testando? Testar não é tão legal assim. Mas é fácil! Tudo que precisamos fazer é executar essa função várias vezes, passando dados diferentes pra ela, e ver como ela se comporta.

Pense que o programa está rodando na web, e você precisa manualmente garantir que ela funcione. Ligue sua mente destrutiva e pense nos vários casos que possam fazer esse programa não funcionar.

Como somos programadores, podemos olhar para o código e ver que ele tem 4 caminhos diferentes (um para cada if, mais o caminho onde nenhum if é verdadeiro). Precisamos executar o programa com cada um deles. Vamos começar com o primeiro, onde ele precisa retornar “fizz” se o número é múltiplo de 5.

Legal! Ele retorna “fizz”. Está funcionando! Mas ainda não está tão automático quanto gostaríamos. Pois, você, ser humano, precisa ver que a resposta saiu certa. Precisamos pedir pra máquina comparar. Afinal, é fácil, sabemos que se a entrada for 5, a saída é “fizz”. Basta compararmos:

Se rodarmos, ele imprime “verdadeiro”. Quer dizer que a comparação deu certo e o programa comportou-se como esperado! Agora vá no código do FizzBuzz, e altere ali “% 5” para “% 6”. Sim, estamos colocando um bug em nosso código. O que acontece agora? Ele imprime “falso”. Ótimo, verdadeiro se está certo, falso se estiver errado.

Parabéns! Você escreveu seu primeiro teste de unidade! Pois é, é simples assim. Basta você pensar em entradas e saídas, e executar seu programa com elas! Agora faça um código parecido para testar a entrada 7. Você sabe que a saída será… “buzz”.

Mas agora vamos fazer isso melhor. Vamos usar o JUnit, o framework hiper-pop de testes de unidade do mundo Java. O que ele faz? Ele é um robô que vai fazer tudo pra mim? Não! Ele não faz muita coisa, além de te ajudar a dizer se seus testes estão passando ou não. Ao invés de imprimirmos verdadeiros ou falsos (que não ia funcionar bem quando tivéssemos 1000 testes desse), ele pinta a tela de verde ou vermelho, e nos mostra qual “sysout” não funcionou.

No Eclipse, é fácil plugar o JUnit. Aperte o botão direito do mouse em cima do seu projeto, escolha a opção Build Path -> Configure Build Path. Na aba Libraries, clique em Add Library. Selecione JUnit -> JUnit 4. E pronto!

Agora basta usarmos. Vamos escrever métodos de teste, um para cada diferente cenário (entrada/saída) que temos para nosso programa. Todo método deve ser anotado com @Test, ser público e retornar void. E aí, no fim, ao invés de fazermos Sysout, usaremos o Assert.assertEquals(), que é quem faz a comparação que garante que a saída bate com o esperado. Veja:

Se você clicar com o botão direito do mouse no código-fonte, e selecionar Run -> Run as JUnit Test, verá uma tela como a abaixo. Verde, ou seja funcionou.

junit

Agora, faça o teste e coloque um bug na aplicação. Adivinha que cor vai ficar?

falhou

Fácil, né?! Agora basta continuarmos a escrever outros métodos de teste, para os vários cenários. Veja:

Legal, né!? Sua máquina agora roda 5 testes mais rápido do que um piscar de olhos! Um ser humano nunca seria tão rápido! Testes automatizados são muito vantajosos:

  • Rodam muito rápido. Você pode ter milhares de testes e ainda assim executá-los todos em apenas alguns segundos.
  • Se rodam rápido, quer dizer que você vai rodá-los o dia todo. Ou seja, quando algum quebrar, você corrigirá mais rápido, pois tudo estará fresco na sua cabeça. Sem testes, você acha um bug muuuito depois de ter escrito o código, e isso torna tudo mais difícil.
  • Não custa caro. A máquina não cobra nada para executar. E você só gasta tempo nele na hora de escrever. Já parou pra pensar quantas vezes você executa o mesmo teste manual ao longo do dia?

Parabéns, você sabe escrever testes automatizados! Será que tem mais!? Aguarde o próximo post.

Um pequeno estudo sobre asserções em testes

Muitas pessoas já ouviram falar da regra “apenas uma asserção por teste” (only one assertion per test), famosa no post do Dave Astels. A regra, como o próprio nome diz, afirma que o programador nunca deve escrever mais de uma asserção pois a necessidade de mais de uma asserção em um teste poderia indicar que o método está fazendo coisas demais.

Há um mês atrás comecei a escrever um post sobre isso, mas meu exemplo era muito fraco. Corri então para olhar testes de alguns dos últimos projetos que participei, e pasmém: na maioria deles só havia uma asserção!

Ao observar os testes que continham mais de uma asserção, percebi que eles aconteciam nos seguintes casos:

  1. Quando o método retorna uma lista, array ou uma classe responsável por armazenar uma coleção de determinado objeto;
  2. Quando o método retorna um novo objeto;
  3. Quando o método é parte de uma DSL;

Nos testes do tipo (1), as asserções mais comuns são para verificar o tamanho da lista e se o elemento existente nela é o esperado. Além disso, se o teste espera mais de um elemento na lista, o teste faz algum tipo de loop para verificar; Nos testes do tipo (2), o método de teste realiza asserções sobre os atributos do objeto retornado; E, finalmente, nos testes do tipo (3), que geralmente testam a DSL, e nesse caso um teste realmente testa mais de um comportamento ao mesmo tempo, e por isso, verifica mais de um comportamento.

Resolvi portanto perguntar a opinião de outros desenvolvedores sobre a regra. Para isso, enviei a pergunta no twitter (de forma não enviesada, perguntando apenas a opinião e, para os que me responderam de volta, exemplos de código aonde isso fizesse sentido).

Algumas pessoas concordaram com a ideia de apenas uma asserção por teste, afirmando que a regra ajuda a manter o código mais simples e mais fácil de manter. Além disso, quando o teste quebra, é fácil perceber o problema.

Outros já discordaram da regra, e afirmaram que o programador deve tentar escrever sempre o menor número possível de asserções, mas que a regra não precisa ser seguida à risca. Discutindo um pouco melhor esse ponto de vista, muitos deles afirmaram que um teste deve testar apenas uma única funcionalidade, não importando o número de asserções necessárias para tal.

Infelizmente a quantidade de códigos enviada foi muito baixa. Mas, o interessante é que um dos códigos enviados se encaixa em (1). Já o outro código enviado, retirado de um livro de Ruby, não se encaixa em nenhum dos exemplos acima, mas pode-se dizer que aquele teste está na verdade testando duas funcionalidades: string com espaços no começo e no fim e string sem espaços.

A ideia desse post é portanto, fomentar essa discussão. Alguém tem um outro exemplo aonde mais de uma asserção por teste faça sentido, mas que não se encaixa nos casos acima?

Agradecimentos

Obrigado ao @elemarjr, @viniciusquaiato, @FabioVazquez, @pedroreys, @pisketti, @danielsilvarj, @carlosgaldino, @rodbv, @cessor, @alexandregazola, que responderam no Twitter.