Criei uma Biblioteca de Requisições e Fluxos de Testes

Uma das grandes maravilhas do Robot Framework é permitir que você crie muitas coisas legais em Python e importe para o framework como Bibliotecas. Isso nos dá a possibilidade de não ficar preso às bibliotecas do próprio Robot Framework, ou à bibliotecas de terceiros. 

Eu mesmo já criei algumas Test Libraries (ou Custom Libraries) para me fornecer recursos que não existiam no Robot Framework, ou que bibliotecas de terceiros me forneciam, mas não da forma como eu precisava.

Aqui nesse post, não vou ensinar a criar uma Test Library, pois é um conteúdo que apesar de simples, é um pouco extenso para estar em uma única postagem no blog. A criação de uma Test Library, estará disponível (em  breve) no Guia da Robot Courses. Ao invés disso, vou contar um pouco da ideia que tive com a criação da última Test Library que criei e que talvez possa te instigar a pensar em coisas diferentes também. 

O Desafio

Pense no seguinte cenário:

Você trabalha em uma equipe que possui várias aplicações Backend, onde a maioria disponibiliza APIs que em conjunto constroem fluxos de negócio para um aplicação Frontend. E nesse contexto, precisamos garantir a qualidade de todas as aplicações do Backend. E assim como as aplicações precisam conhecer suas fronteiras de negócio, os testes também precisam entender as fronteiras da aplicação testada para entender falhas encontradas e sinalizar de forma correta sem gerar falsos positivos.

Como os testes serão executados na camada de aceitação, criar Mocks passa a não ser uma boa prática. Pois nessa camada a ideia é validar o fluxo integrado entre as aplicações em um ambiente que consiga simular Produção.

Bom, acredito que muitos de vocês já vivenciaram esse tipo de desafio, é algo relativamente comum nas empresas atualmente. E para vencer esse desafio, costumamos adotar algumas soluções, a nível de estrutura, para criarmos as automações dos testes de aceitação e garantirmos continuamente a qualidade destas aplicações.

Então, vamos falar um pouco sobre duas que eu já fiz e que geralmente vejo outros QAs adotando.

As Soluções

  • Criar um repositório separado para testar todas as aplicações.

Uma das soluções que mais vejo, é a criação de um repositório separado dos repositórios das aplicações que serão testados, fazendo algo como um monolito de testes. E será de responsabilidade desse monolito testar todas as aplicações.

Essa forma funciona bem, desde que não existam muitas equipes trabalhando no mesmo projeto de automação. Caso exista, há grandes chances de criarmos conflitos nas Branches principais do projeto de automação, e conforme o projeto cresce, a dificuldade de evolução em conjunto com a aplicação e a complexidade de manutenção tendem a aumentar constantemente.

  • Criar os testes dentro dos repositórios das aplicações

Outra solução que vejo bastante é a criação dos testes de aceitação dentro dos repositórios de cada aplicação testada.

Até então, essa era a forma que eu também adotava para criar minhas automações. Pois assim, os testes conseguiriam evoluir em conjunto com a aplicação, usando as mesmas Branches para evoluir tanto a aplicação quanto o teste em relação a regras de negócio e a cenários de testes, e consequentemente fazendo com que a automação seja parte integrante do gitflow do projeto. Porém, também tem algumas ressalvas.

Enquanto na estrutura anterior, existe um reaproveitamento maior das Users Keywords por ser basicamente um “monolito de testes“. Aqui nessa estrutura, de forma inevitável teremos repetição de código em repositórios diferentes.

Imagine que a Aplicação 1 é um sistema de autenticação que gera um token de acesso, e que as demais aplicações (2, 3 e 4) precisam desse token para que possam gerar suas respostas com sucesso. Nesse caso, a User Keyword que vai executar a API de autenticação precisará ser desenvolvida em todos os repositórios. Então a chance de começarmos a criarmos o mesmo recurso de formas diferentes para o mesmo fim, começa a aumentar.

Saindo da Bolha

Agora, explicando melhor a ilustração principal deste post (rs). Imagine que qualquer pessoa possa ter acesso à uma única “prateleira de robôs“, e usá-los conforme a necessidade. E essa “prateleira de robôs” te dará a oportunidade de evitar retrabalho, pois todos os robôs que você precisa, sempre estarão nessa “prateleira“, independente de onde você esteja, desde que você tenha acesso à eles.

FILOSÓFICO DEMAIS NÉ… 😲? Vamos desenrolar essa ideia…

Agora, pense que essa “prateleira de robôs” é um grande pacote Python com várias Test Libraries (ou Custom Libraries) organizadas de forma que entreguem Keywords que representem cada endpoint de um determinado Controlador das APIs. E que “qualquer pessoa” sejam os repositórios que baixem esse pacote Python via Poetry.

A imagem abaixo ilustrar melhor a ideia.

Para fazer isso, basicamente deixei para trás a RequestsLibrary, que é a biblioteca mais famosa para execução de testes de API para Robot Framework. E usei alguns recursos da API do Robot Framework para criar esse grande pacote. E também usei o Poetry para auxiliar na distribuição deste pacote, via GitHub (por ser algo inerente ao projeto de onde trabalho, o PyPi não seria o lugar ideal para distribuir esse pacote).

Também criei uma subdivisão entre as bibliotecas, dando responsabilidade distintas:

  • Bibliotecas de Requisições: Disponibiliza Keywords que irão executar as requisições e retornar um response. Sem que nenhuma validação de negócio seja feita.
  • Biblioteca de Testes: Disponibiliza Keywords que são capazes de executar fluxos completos utilizando as funções criadas para as Bibliotecas de Requisições para executar todo o fluxo de negócio no qual o endpoint em teste está inserido. Além de saber quais são as regras que precisam ser validadas baseadas nos dados recebidos e principalmente saber identificar quando uma falha no fluxo de teste é proveniente do endpoint alvo do teste – gerando um status Fail – ou dos endpoints  quem fazem parte do fluxo, mas não são alvo do teste – gerando um status Skip -.

Com base nisso, a estrutura de packages desse projeto ficaria dessa forma:

.
├───NomeDoModulo
│   ├───Requests
│   │   ├───Aplicacao1
│   │   │   └───__init__.py
│   │   │   └───_BaseClass.py
│   │   │   └───Controller_X.py
│   │   ├───Aplicacao2
│   │   │   └───__init__.py
│   │   │   └───_BaseClass.py
│   │   │   └───Controller_Y.py
│   │   ├───Aplicacao3
│   │   │   └───__init__.py
│   │   │   └───_BaseClass.py
│   │   │   └───Controller_Z.py
│   │   ├───Aplicacao4
│   │   │   └───__init__.py
│   │   │   └───_BaseClass.py
│   │   │   └───Controller_W.py
│   │   └───__init__.py
│   ├───Tests
│   │   ├───Aplicacao1
│   │   │   └───__init__.py
│   │   │   └───ControllerTest_X.py
│   │   ├───Aplicacao2
│   │   │   └───__init__.py
│   │   │   └───ControllerTest_Y.py
│   │   ├───Aplicacao3
│   │   │   └───__init__.py
│   │   │   └───ControllerTest_Z.py
│   │   ├───Aplicacao4
│   │   │   └───__init__.py
│   │   │   └───ControllerTest_W.py
│   │   └───__init.py__
│   │   └───_TestClass.py__
│   └───__init.py__

Com o projeto publicado no GitHub, podemos usar o Poetry para baixar o pacote e inseri-lo como dependência de um projeto de automação.

Como é um único pacote com várias bibliotecas, a importação é um pouco diferente do normal, pois precisamos navegar até o módulo que possui as Keywords que serão utilizadas nos testes. 

Então, no exemplo da estrutura que estamos usando, ficaria algo como:

*** Settings ***
Library  NomeDoModulo.Requests.Aplicacao1.Controller_X  AS  Controller_X
Library  NomeDoModulo.Tests.Aplicacao1.ControllerTest_X  AS  ControllerTest_X

Como o nome da biblioteca ficou grande devido a navegação dentro do módulo, é recomendável o uso de um “alias” para ajudar na identificação da biblioteca.

Agora, imagine que no exemplo que estamos usando, temos uma função construída para servir de Keyword no “Aplicacao1.Controller_X.py“. Então, teríamos algo como:

*** Settings ***
Library  NomeDoModulo.Requests.Aplicacao1.Controller_X  AS  Controller_X
Library  NomeDoModulo.Tests.Aplicacao1.ControllerTest_X  AS  ControllerTest_X

*** Test Cases ***
Cenário: Controller_X
    [Documentation]  Keyword que executará uma requisição baseada nos dados recebidos e retornará um 
    ...  response
    
    ${response}   Controller_X.Post Cart
    ...  authorization=XPTO_123
    ...  id_user=USER_123
    ...  device_id=DEVICE_456
    ...  products_id=['90110', '55534']
    ...  quantities=[1, 2]
    ...  store_id=ABC_123
    

Cenário: ControllerTest_X
    [Documentation]  Keyword que executará todo o fluxo de teste para o endpoint da keyword
    ...  baseado nos dados recebidos
    
    ControllerTest_X.Test Post Cart
    ...  products_id=['90110', '55534']
    ...  quantities=[1, 2]
    ...  store_id=ABC_123

Perceba que, no primeiro cenário, apenas uma requisição será executada, sem validações. Para caso queria realizar os asserts dentro do projeto em teste e não dentro da biblioteca. E no segundo cenário, somente alguns dados relevantes ao testes são passados, os demais são coletados no fluxo montando dentro da Keyword, assim como os asserts usando a api BuiltIn do Robot API.

Conclusão

Com essa estrutura, consegui de uma certa forma centralizar em apenas um lugar todos os recursos de testes que todas as aplicações precisam. Ganhei aqui mais facilidade na manutenção, já que tenho um único repositório para fazer grandes manutenções, em caso de mudanças (as keywords sofreram mudanças apenas se possuírem argumentos e se esses argumentos forem alterados). A biblioteca, até a data desse post, também substituiu todos os meus arquivos de recursos (arquivos de Keywords e arquivos de Variáveis). Além de possibilitar uma vasta documentação utilizando o LibDoc, para documentar cada biblioteca e suas keywords com base nas DocStrings de cada função Python.

Então, sim, até aqui está sendo uma estratégia de estrutura extremamente valiosa, agradável e desafiadora.

Observações sobre o Post

Obviamente, não coloquei tudo nesse post, pois se tornaria um mini livro em formato de post, e acabaria se tornando uma leitura super maçante para vocês. A ideia desse post é mostrar que é possível sair da bolha e criar coisas incríveis com Robot Framework. E provocar vocês a sair da bolha também, e buscar conhecer mais a fundo o Robot Framework a ponto de se libertar de uma biblioteca famosa, como fiz com a RequestsLibrary.

Caso eu perceba que ficaram interessados e esse post tenha um engajamento legal, posso tentar criar um Vídeo Book explicando todas minúcias dessa estrutura. Mas acredito que, com o que já foi explicado nesse post, seja um bom início para tentarem criar algo muito bacana.

É isso pessoal … 

E ai, curtiram essa estrutura? Ou acharam uma ideia maluca? 😂

Deixa aqui seu comentário!

Nos vemos no próximo post!
VALEU

\o/

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *