Testes de Interface com Selenium e Page Objects 9
ALOHA!
Olá Pessoal! Só pra quebrar um poquinho vou fazer um post um pouco mais "técnico". O Willi falou nos últimos posts sobre algumas das experiências obtidas com o uso de metodologias Ágeis no projeto SIGADAER da Aeronáutica. Acredito que boa parte deste "sucesso" é devido ao uso intensivo de desenvolvimento orientado à Testes. Semprei levei o uso de testes automatizados a sério, e aqui no projeto não foi diferente. Conseguimos evoluir, refatorar e detectar impactos com muita facilidade depois da implementação de um TestSuite com qualidade e cobertura de código significativa.
Hoje contamos com aproximadamente 180 casos de teste, entre unitários e de Interface. Vou falar um pouquinho sobre como implementamos os testes de Interface, utilizando o Selenium (IDE, RC e Server), o bom e velho Junit e o padrão de PageObjects. Sempre escrevendo o Teste de aceite junto com um StakeHolder antes tudo.
Ambiente:
Pra esse pequeno exemplo vamos utilizar a IDE Eclipse, o Selenium-IDE para gravar as funcionalidades de cada PageObject, e as versões 0.91 do Selenium Remote Control e Selenium Server. Logo ali eu falo um pouquinho sobre esses dois últimos. O projeto do eclipse com fontes e libs está disponível aqui.
O Selenium-IDE é um plugin fantástico para o Firefox. Com ele você pode gravar os testes executando as funcionalidades do sistema e exportar os Casos de Teste para Java, Html, PHP, Ruby e mais uma série de linguagens que o Selenium Server e Remote Control dão suporte. Sem programar uma linha de código sequer.
Vamos começar pela configuração do Selenium Server. O selenium Server funciona como um mini container que manipula as requisições HTTP entre o browser (no caso o Firefox) utilizado nos testes, e as classes de Teste que solicitam as requisições para o browser. Aqui nós criamos este arquivo properties para externalizar alguns parâmetros de configuração:

Em seguida criamos um Singleton para o Selenium Server para aproveitar o browser entre os testes e configurar o server com os valores do properties.

Agora temos uma classe para Testes Selenium que estende um TestCase Junit. Nossoas classes de teste de Interface vão estender deste cara aí Os métodos que interessam são o startSeleniumServer(), que inicia o servidor selenium e a sobrescrita do setUp(), que abre o contexto a ser utilizado nos testes.

Very Nice! Nossa infra de testes está quase pronta. Como eu já citei lá em cima, nós sempre escrevemos um "Teste de Aceite" antes de tudo. Ao escolher uma estória a ser implementada, identificamos os cenários e escrevemos o que cada cenário deve cotemplar. Ali no javadoc mesmo, sem frescuras. Assim nós sabemos que se o nosso teste passar, a estória tá pronta, simples assim.
Então vamos começar com um teste bem simples. Imagine a estória "Efetuar Login" do portal da Sea. Vamos escrever um caso de teste que contemple o cenário de falha no login. Taí o cabra:

Beleza! Já sabemos o que o teste tem que "testar". E aí? Agora entra em cena o Selenium IDE. É só abrir o console da IDE, setar a linguagem de programação a ser utilizadada (Java no caso) e mandar o bixo gravar. A partir daí você pode executar o fluxo normalmente e o Selenium vai gravar o TestCase já na linguagem escolhida, aí é só copiar e colar.

Beleza de novo! Mas e os asserts? Moleza de novo! O plugin conta com um menu de contexto contendo algumas validações que podem ser feitas naquela página. Você pode fazer asserts com valores de campos de tabelas, links, alerts e confirms javascript, títulos, basicamente todo o conteúdo da tela está disponível para manipulação através da api Java do selenium. O que não estiver no menu de contexto pode ser facilmente descoberto com uma olhadinha rápida na api.

Mas é aí que a gente esbarra com um pequeno probleminha. Eu poderia simplesmente usar o selenium direto nos meus testcases, mas a mudança de um label de um botão poderia quebrar todos os testes. O Brunão me mandou este link de um post muito interessante falando um pouco sobre PageObjects. Usando este padrão, podemos implementar classes que representam as interfaces gráficas, encapsulando o uso do selenium, aumentando drasticamente a manutenabilidade e deixando os testcases extremamente "limpos" e legíveis. Por exemplo, vejamos o nosso TestCase de Login já implementado com PageObjects:

Claro que este é um exemplo extremamente simples. Mas dá pra sacar como as coisas ficam transparentes. Vejamos outro exemplo:

E por aí vai! O Selenium é realmente uma ferramenta muito interessante. Se você também leva a sério a idéia de ter um sistema bem testado, com a possibilidade de saber com muito mais precisão qual o impacto de mudanças e refactorings, vale a pena dar uma conferida. O exemplo disponível pra download tá prontinho pra rodar.
Abraço e até a próxima!
Show Rafa, valeu!
Legal notar que a idéia de escrever a “intenção” dos testes em comentários é usada pra que a gente possa levantar os testes de aceitação com o cliente, no comecinho da iteração.
Como escrevemos testes, e não código, economizamo tempo do cliente e não sofremos com o fato das telas ainda não existirem, o que dificultaria a escrita do teste…
Bom demais!
Post estupendo, Fófis. Muito legal. Meus parabéns pelo trabalho.
Grande contribuição para a Engenharia de Software e iniciativa que vai de encontro a maior satisfação dos clientes (adquirentes/consumidores de sistemas de softwares)!!
Rafael,
Muito legal esse post!
Ainda estamos engatinhando em relação aos testes aqui na Previdência, mas já tem gente engajada em mudar esta situação.
Valeu pela contribuição…
Parabéns Fofis!
Ficou Excelente!!!
Queria ter um filho assim! ;)
Depois seria legal fazer um post e mostrar a facilidade que vocês têm de achar os impactos de uma mudança/implementação nova em código testado.
Abraço! Willi
Fantástico, Rafa. Parabéns pelo post!
“Semprei levei o uso de testes automatizados a sério, e aqui no projeto não foi diferente.”
Interessante como conseguimos fazer grandes coisas quando nos dispomos a fazer o necessário todos os dias e aos poucos.
Abraços da Carol.
Pessoal, vale um complemento. Estou aqui tentando incluir as libs do selenium como dependencias do maven, e não se acha as coisas muito bem documentadas por aí.
Eles tem um repositório do maven próprio, em http://archiva.openqa.org/repository/releases/
Adicionando esse repo no pom, eu consegui compilar as classes SeleniumTestFactory e TesteSelenium apenas com a dependencia
Agora vamos ver se funciona ;-)
Muito bom parceiro!! Pode começar a escrever os testes do Selenium pra nossa app então :)
Muito bom seu post!!!!
Me ajudou bastante!O legal é que como escrevemos testes, e não código, economizamo tempo,além de facilitar muito!!!
Abraços da Fih…..