Quando falamos em testes automatizados, o que vem primeiro à cabeça? Testes que simulam o usuário utilizando uma aplicação, através da UI (User Interface)? Testes de unidade (ou unitários)? Neste post, vamos mostrar os níveis de testes automatizados dentro do Agile e como melhorar a estratégia de automação de testes da sua empresa.

Em empresas que estão começando a trabalhar com testes automatizados, é comum vermos o uso de ferramentas do tipo record-playback, como o Selenium IDE, para criar scripts de testes validando cenários de ponta-a-ponta em uma aplicação, através da UI. Esses testes também são chamados de Testes de Aceitação. Ferramentas como essas facilitaram bastante a criação desses testes, permitindo até que um usuário possa gravar um teste, sem requerer skills de programação. Soluções pagas, como as da IBM, HP e Microsoft, também oferecem ferramentas desse tipo.

Infelizmente, também é comum cair na "tentação": gravar centenas de testes que navegam pela UI, só percebendo que algo está errado quando um novo campo é incluído em uma tela, ou quando o identificador de um elemento é alterado, por exemplo. A médio/longo prazo surgem os problemas: o custo de manutenção se torna alto, os testes demoram muito para rodar (aumentando tempo de build) e dar feedback sobre o sistema, muitos testes falham devido a falsos negativos, etc.. Com isso, o time acaba perdendo a confiança nos testes e, muitas vezes, deixando de rodá-los.

Essa preocupação com o tempo de build e de feedback dos testes não vem dos dias de hoje. No XP (Extreme Programming), na parte sobre Integração Contínua [1], já se falava da importância do "10-minute build". James Shore, no livro The Art of Agile Development, cita o "10 or 15-minute build", que seria o tempo máximo razoável para obter feedback do seu build. Em suas próprias palavras, "That's about the right amount of time to stretch my legs, get some coffee, and talk over our work with my pairing partner". O assunto é tão relevante, que Dan Bodart, em sua palestra Crazy Fast Build Times – Or when 10 seconds starts do make you nervous, mostra maneiras de reduzir em até dez vezes o tempo de build de uma aplicação.

Em empresas que possuem times ágeis, testes de unidade (e também o TDD) já nos ajudam muito nessa situação. Quando temos uma boa quantidade de testes de unidade para um sistema, se faz menos necessário automatizar testes tão exaustivos pela UI. Testes de unidade são fáceis de manter, são muito efetivos para testar valores limite ou possíveis combinações de desvios dentro do código e rodam extremamente rápido, nos dando um bom feedback sobre nosso sistema em pouco tempo. Porém, por definição, estamos testando comportamentos de componentes isolados, de forma que uma hora ou outra deveríamos testar a integração entre eles, certo? Logo, criamos então um teste que navegue pela UI para validar isso? Não!

Pirâmide de Automação de Testes

Em seu livro Succeeding with Agile, Mike Cohn descreve o conceito da Pirâmide de Automação de Testes (Test Automation Pyramid).

Pirâmide de Automação de TestesSegundo Cohn, uma estratégia eficiente de testes automatizados deve contemplar testes em três níveis: Unidade, Serviço (Integração) e UI. Na base da pirâmide, temos uma grande quantidade testes de unidade, que devem ser a base de uma boa estratégia de testes automatizados. No topo, uma quantidade pequena de testes de UI, justamente para evitar os problemas que comentamos anteriormente. No meio, temos uma quantidade razoável de testes de serviço, que também podem ser chamados de testes de integração, API Tests, etc.. Cohn, no artigo The Forgotten Layer of the Test Automation Pyramid, comenta sobre a importância desse nível de teste e seu papel em preencher o gap entre unidade e UI.

Testes na camada de serviço testam, basicamente, os serviços da aplicação, “abaixo” da UI. Essa abordagem evita com que todo teste, além do teste de unidade, seja executado diretamente navegando pela interface do usuário. Com isso, em vez de executarmos testes exaustivos validando todas as regras de negócio pela interface, podemos fazer testes abaixo da UI. Esse tipo de teste tem sido muito importante, visto que muitas aplicações hoje em dia possuem interfaces Web e Mobile (smartphone, tablet), sendo necessário separar a interface da lógica da aplicação. Martin Fowler se refere a esses testes com o nome de Subcutaneous Tests.

Dentro do Agile, podemos fazer esses testes para validar os critérios de aceite das histórias, por exemplo. Uma boa abordagem é o uso de BDD (Behaviour-Driven Development) [2]. Para aplicações Java, existe o Arquillian, que tem diversos recursos para criação desses testes, além de extensões que ajudam na criação de testes com Selenium WebDriver e Page Objects.

 

Testes na UI

Com testes na camada de serviço, não precisamos validar todas as regras de negócio de um sistema pela UI. Podemos focar esses testes em funcionalidades críticas (Smoke Tests), em testes que validem aspectos da interface, ou em testes com diversos browsers (xBrowser Testing). Smoke Tests formam o subconjunto dos testes mais importantes, que garantem que a aplicação está realmente OK. O ISTQB (International Software Testing Qualifications Board) os define como:

                "Subconjunto de todos os casos de testes definidos/planejados que cobre as principais funcionalidades de um componente ou sistema, para averiguar as principais funções de um programa em funcionamento sem se preocupar com maiores detalhes."         

Quando concentramos os testes automatizados para a camada de UI, como descrevemos no início do post, em vez de termos uma pirâmide, temos o chamado "Ice-cream Cone", vide figura abaixo:

ice-cream cone

 

 

 

Como evitar os problemas de testes na UI?

1. Uso do pattern Page Objects

Padrão preconizado pelo próprio Selenium, que propõe separar os testes da complexidade da UI, melhorando a legibilidade, manutenibilidade e reusabilidade do código.

Importante: Tratar código de teste como código de produção!

2. Uso de Headless Browsers

Headless Browsers funcionam da mesma forma que browsers comuns, com a diferença de não ter uma interface gráfica. São mais rápidos para testes e são muito bons para usar com Integração Contínua. Hoje em dia, o mais popular é o PhantomJS, que utiliza a engine gráfica WebKit, a mesma usada pelo Google Chrome. Há também o SlimerJS e o HtmlUnit.

Frameworks e headless browsers suportados:

 

 3. Uso de BDD

Existem diversos frameworks para ajudar na adoção de BDD, como:

 

 4. Paralelizar testes

É possível rodar testes em paralelo, diminuindo bastante o tempo de execução. Pode-se usar TestNG, Maven e Selenium Grid para tal.

 

Finalizando, recomendo a leitura do artigo Eradicating Non-Determinism in Tests, do Martin Fowler e da palestra Lições do Futuro: O que eu queria saber há alguns anos atrás sobre como manter uma suíte de testes, do Eder Ignatowicz e Fabio Santos, apresentada nas edições 2012 e 2013 do TDC. Compartilhem suas dúvidas nos comentários!

 


Referências:

http://www.mountaingoatsoftware.com/blog/the-forgotten-layer-of-the-test-automation-pyramid

http://martinfowler.com/bliki/TestPyramid.html

[1] http://blog.myscrumhalf.com/2012/06/a-integracao-continua-utilizada-no-dia-a-dia-do-desenvolvimento-agil/

[2] http://blog.myscrumhalf.com/2011/10/bdd-%E2%80%93-foco-no-comportamento-do-sistema/