Category Archives: Blog em Português

Maus cheiros em códigos de teste… Eles existem!

Acabei de ler um paper muito legal sobre code smells em código de testes [1]. Resumindo aqui os resultados:

  1. Maus cheiros em testes não são percebidos pelos desenvolvedores como problemas reais de código. Ou seja, desenvolvedores não costumam enxergá-los como problemas.
  2. Na maioria dos casos, as classes de teste são afetadas pelos smells desde o momento da sua criação. Ou seja, a maioria dos testes mal escritos foram mal escritos desde o começo.
  3. Os maus cheiros tem uma taxa de sobrevivência altíssima. Ou seja, o mau cheiro fica lá no código por muito tempo, até alguém decidir refatorá-lo.
  4. Existe uma relação entre maus cheiros no código de teste e maus cheiros no código de produção. Ou seja, código de produção ruim faz com que desenvolvedores escrevam testes problemáticos também.

Você quer ler mais sobre possíveis maus cheiros em código de teste? Então veja o excelente paper do Arie van Deursen et al. [2], onde eles listam diversos maus cheiros que podem acontecer nesse tipo de classe.

[1] Tufano, M., Palomba, F., Bavota, G., Di Penta, M., Oliveto, R., De Lucia, A., Poshyvanyk, D.Towards Automated Tools for Detecting Test Smells: An Empirical Investigation into the Nature of Test Smells. In 31st Automated Software Engineering, 2016. Link aberto pro paper.

[2] A. van Deursen, L. Moonen, A. Bergh, and G. Kok. Refactoring test code. In Proceedings of the 2nd International Conference on Extreme Programming and Flexible Processes in Software Engineering (XP), pages 92–95, 2001. Link aberto pro paper.

O que são testes de mutantes?

Como garantir que nossa bateria de testes está boa? Essa é uma pergunta importante, afinal de nada adianta termos testes automatizados se eles não forem bons o suficiente. Uma maneira bem conhecida é calcular a cobertura do código. Ferramentas como o Cobertura dizem pra você quais linhas do seu código de produção não são executadas pela sua bateria de teste. Assim, você pode facilmente ver qual if você esqueceu de testar, e escrever um teste pra ele.

Mas essa não é a única maneira. Uma delas, bastante interessante e muito popular na academia (mas não tão popular na indústria) é o teste de mutante. A ideia é genial. Imagine que tenhamos testes verdes para o seguinte trecho de código:

Veja que o if verifica se a é MAIOR que 10. O que deveria acontecer com os testes se mudássemos o sinal de MAIOR para MENOR? Nossa bateria de testes deveria quebrar, certo? Pois é exatamente isso que testes de mutantes fazem. Um mutante é simplesmente uma versão alterada do seu código de produção. Alterar o sinal de maior para menor é uma maneira de gerar um mutante. Mudar o sinal de + pra -, * por /, e assim por diante. E a ideia é que, se rodarmos os testes trocando a classe por um mutante, algum teste deve falhar. Afinal, o mutante faz coisa errada!

Ferramentas como o Pitest pegam seu código de produção, geram diferentes mutantes, e executam a bateria de testes. Se algum teste falha, dizemos então que o mutante foi morto. Agora, se algum mutante sobrevive, então você precisa melhorar seus testes.

Para exemplificar, veja meu repositório pitest-fizzbuzz. Ele tem uma simples implementação do jogo Fizz Buzz. É o mesmo exemplo que usei na pequena série de começando com testes, aqui no meu blog. Você entenderá o jogo pelo código:

Veja os testes dele (que fizemos juntos no blog):

A bateria de testes parece bem completa. Veja o resultado do relatório emitido pelo Pitest. Tudo verde, ou seja todos os mutantes foram mortos (ahá, eu mandei bem quando escrevi os testes! 🙂

pitest-sucesso

Agora, vamos supor que tivéssemos esquecido o teste deveRetornarFizzBuzzQuandoMultiploDe5e7(). Olha só o relatório. Ele nos mostra bem a linha do código de produção onde ele fez a mutação (nesse caso, as mutações), a descrição, e mostra que o mutante sobreviveu. Nesse caso, ele mudou o % por *, e nenhum teste pegou.

pitest-erro

Até aí, parece que o cobertura também pegaria isso. Afinal, essa linha não foi coberta. No entanto, testes de mutantes vão além. Mas imagine uma nova regra no jogo: Números maiores ou iguais a 500 imprimem “big”. Implementamos:

E adicionamos o teste:

Agora, a cobertura desse código é 100%.

pitest-cobertura

No entanto, veja o teste de mutante. Ele pegou! Afinal, não testamos o caso do igual no maior-ou-igual. Uma mutação ali (trocar por exemplo para só maior), e o mutante sobrevive!

pitest-erro3

Testes de mutantes são bastante interessantes, e ainda muito desafiadores para a academia. Afinal, em um sistema grande, o número de mutantes pode ser muito grande. Como encontrar os melhores mutantes? Como remover mutantes redundantes? No site do pitest, você pode ler um pouco mais sobre mutantes e ver as operações de mutação que ele implementa.

A ferramenta tem plugin para o Maven, então é fácil de executar. No repositório de exemplo, o pom.xml está configurado.

Como você usa pré-processadores CSS?

Pré-processadores CSS estão na moda. Afinal, eles dão poder para CSS que, por natureza são simples, mas nada fáceis de manter. O pessoal da Universidade de Concórdia acabou de fazer um estudo empírico bem legal sobre o uso de SASS e LESS.

De forma resumida, os resultados encontrados foram:

  • Desenvolvedores declaram principalmente variáveis globais (89% dos casos), especialmente para armazenar cores (45% dos casos).
  • Aninhamento (nesting) é bastante popular. 78% dos seletores são aninhados.
  • 2/3 dos mixins são reusados duas ou mais vezes. Interessantemente, 42% deles são usados para lidar com propriedades específicas de browsers (-webkit-*, etc).
  • Desenvolvedores preferem mixins sem parâmetros do que usar herança.

O artigo vai mais a fundo, sugerindo razões e possíveis ferramentas focadas para ajudar desenvolvedores nessas situações (refatorações, por exemplo). Você pode ler mais no preprint do artigo que será apresentado no SANER 2016:

E aí? Os números são o que você esperava? Ou você faz diferente?

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.

Como você usa construtores?

Construtores são legais, afinal, eles nos permitem garantir que uma classe não será instanciada sem alguns dados básicos. No entanto, a dúvida sempre aparece: o que devemos passar pelo construtor e o que devemos passar pelo método?

Bem, minhas regras pessoais são:

  • Se a classe é uma entidade, então eu peço no construtor todos os dados necessários para que a entidade seja válida. Por exemplo, Pessoa precisa de nome, vai pelo construtor.
  • Se a classe não é uma entidade, e ela precisa de “ferramentas de trabalho” (outras dependências, como DAOs, etc), eu as passo todas pelo construtor, sempre. Já os valores que serão utilizados ao longo do processamento, eu passo sempre pelo método.
  • Se algum dos frameworks que estou usando me obrigar a ter um construtor default, eu o crio, com a menor visibilidade possível, e o anoto com @Deprecated.
  • Se estou refatorando algum código legado, não me incomodo de ter um construtor padrão, fazendo alguma ação padrão.
  • Se minha classe aceita diferentes combinações de valores obrigatórios, tenho diferentes construtores. Em entidades, se tenho atributos não obrigatórios, às vezes crio dois construtores, recebendo e não recebendo aquele atributo. Depende da situação.

Acho que é isso. Se vc tiver as suas regras, estou curioso para conhecê-las!

Desenvolvedores e Testes Automatizados em suas IDEs

Será que fazemos o que falamos? Falamos o que fazemos? Em um estudo bastante interessante, os pesquisadores monitoraram programadores usando o Eclipse, e vejam o que encontraram:

  • A maioria dos projetos e usuários não praticam testes ativamente.
  • Desenvolvedores, em sua maioria, não rodam testes na IDE. Mas quando o fazem, fazem com muita frequência.
  • Código de testes e código de produção não co-evoluem de maneira elegante.
  • Testes que são executados na IDE rodam muito rápido.
  • Desenvolvedores comumente executam apenas um conjunto específico de testes. Na maioria dos casos, os desenvolvedores executam apenas um teste.
  • A maioria das execuções de testes dentro das IDEs falham.
  • A reação mais comum a um teste falhando é mergulhar no código de produção culpado.
  • TDD não é amplamente praticado. E os programadores que dizem fazer, não o fazem estritamente e nem para todas as modificações.
  • Desenvolvedores gastam um quarto do seu tempo trabalhando em testes. Curiosamente, eles acreditavam que esse número era o dobro maior.

E o mais legal: os resultados observadores contradizem as respostas que esses mesmos desenvolvedores deram em uma survey.

E você? Como faz!? 🙂

Beller, Moritz, Georgios Gousios, Annibale Panichella, and Andy Zaidman. “When, how, and why developers (do not) test in their IDEs.” In Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering, pp. 179-190. ACM, 2015.

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.