Camadas de abstração para projetos de automação
Apresentarei neste artigo como organizo as camadas de abstração dos meus projetos de automação, sem atrelar uma tecnologia específica e sem me propor a detalhar os conceitos do padrão de arquitetura PageObject, assumindo que o leitor já está familiarizado com ele. As ideias propostas aqui não se aplicam somente para interface web, mas para qualquer outra tecnologia de interface que possa ser automatizada, bem como mobile, Java Swing, etc.
Scripts automatizados para um sistema que será submetido a atualizações sempre necessitarão de manutenção. É nossa responsabilidade lidar com isso e pensar no design de nosso projeto, preparando o código fonte para que essas tarefas, as quais normalmente são executadas por outros profissionais, se tornem o mais simples possível. Códigos confusos e de difícil alteração tornam-se um estorvo para a equipe e provavelmente serão abandonados rapidamente após as primeiras atualizações do sistema, devido ao acúmulo de alterações necessárias.
Separo as responsabilidades dos componentes em meus projetos, independente da linguagem, ao menos em três níveis: os elementos da página ou aplicação, que é a camada de page objects; as ações das funcionalidades do sistema, que é a camada por vezes chamada tasks, outras vezes chamada de resources, ou algo equivalente; e por fim os cenários de teste escritos em linguagem humana amigável, que é a camada de test cases.
Essa é a estrutura básica que todo e qualquer projeto de automação de interface deve seguir, facilitando que outros programadores consigam dar manutenção e continuidade ao projeto por estarem familiarizados com sua arquitetura, mesmo que não estejam acostumados com determinada linguagem de programação. Além disso, o código fica mais legível e reaproveitável, aspectos que também melhoram a manutenabilidade dos scripts.
Cada camada possui uma responsabilidade e uma razão de existir. Falaremos um pouco sobre cada uma delas:
A responsabilidade da camada de page objects é prover os elementos de uma página, encapsulando seus mapeamentos. Esses elementos, também chamados de objetos, podem ser botões, campos de texto, imagens, checkboxes, dentre outros. Para melhor organização e manutenabilidade, criamos um arquivo para cada página ou tela do sistema ou aplicação, por exemplo LoginPageObject, ShoppingCartPageObject, ContactPageObject ou MyWishListPageObject. Não devem haver dados, ações ou validações dentro dos page objetcs.
Avançando um nível de abstração, chegamos à camada intermediária, as tasks, resources, ou outras nomenclaturas que eventualmente podem variar. A responsabilidade aqui é encapsular as ações do sistema, divididas por funcionalidades, como CheckoutTasks ou LoginTasks. Esses métodos é que interagem com os elementos dos page objects. Nesta parte é onde existirão maiores nuances de modelagem por parte do programador, que optará por criar ações mais ou menos genéricas, como “realizar login” ou “preencher nome de usuário”, “preencher senha” e “clicar no botão ‘Entrar’”. Observo que quanto mais atômica a ação, maior a possibilidade de reaproveitamento do código. Não devem haver dados dentro das tasks/resources. Tenha em mente que alterando os dados, um fluxo de “realizar login” pode ser reutilizado para cenários de sucesso ou falha por username incorreto, senha incorreta, usuário inativo ou dados inválidos, por exemplo.
Chegamos à camada de abstração mais alta até então, a camada dos test cases, os quais, não raro, estarão contidos dentro de uma test suite. Aqui o código fonte deve ser facilmente legível, e, se possível, escrito em linguagem amigável para o ser humano, como na sintaxe Gherkin, por exemplo. Desta forma, ao ler o caso de teste, uma pessoa deve conseguir, sem dificuldades, compreender o passo-a-passo de ações realizadas.
Todavia, ainda podemos evoluir este modelo simplificado criando algumas outras camadas de responsabilidades. Citarei mais duas: uma para isolar os pontos de verificação dos scripts, chamada justamente verification points, e outra para os dados de teste, esta que poderia ser um gerador de dados (dataprovider), ou um conjunto de dados pré-armazenados (datapool), ou um acesso de leitura em banco de dados (database), ou requisições para uma API de serviços (services), etc., dependendo do contexto do projeto.
Os pontos de verificação funcionam como as tasks, encapsulando ações e interagindo com elementos da tela, contudo, a sua responsabilidade é representar ações específicas de validação. Sem validação, o script automatizado não deveria ser considerado um teste, afinal de contas, testes servem para validar alguma coisa.
Geralmente, os dados de teste são o principal problema para o desenvolvedor de testes automatizados. A técnica de como acessar dados que contemplem pré-requisitos varia muito em cada time e empresa. Esses dados podem ser obtidos através de consultas de leitura em banco de dados, requisição à serviços, etc. No caso de dados livres de contexto a tarefa é facilitada, de maneira que podemos gerar dados dinamicamente através de bibliotecas como o Faker.
O fato é que misturar acesso ou geração de dados com as tasks ou test cases provocará confusão e redundância de código. Então, ao invés de criar tasks para “realizar login com sucesso”, “realizar login com nome de usuário inválido” e “realizar login com senha incorreta”, deve-se criar apenas uma task “realizar login” que receberá os dados através da invocação nos três casos de teste, que apenas repassam os dados para a task. A responsabilidade de gerar ou buscar estes dados deve estar encapsulada em uma camada de dataprovider, datapool, database ou service, dependendo do caso.
Espero que tenham desfrutado deste artigo. Sintam-se à vontade para opinar e criticar, enriquecendo o debate sobre as melhores práticas no desenvolvimento de projetos de automação.
Referência:
FOWLER, Martin. PageObject. Disponível em martinfowler.com/bliki/PageObject.html (acesso em 24 de setembro de 2022).
Selenium Documentation: Page object models. Disponível em selenium.dev/documentation/test_practices/encouraged/page_object_models/ (acesso em 20 de setembro de 2022).