Desenvolvendo Testes de Integração
Inicialmente devemos destacar a importância da atividade de testes em todas as camadas do desenvolvimento, neste artigo iremos focar nos testes integrados de sistema em API’s. Estes testes muitas vezes trazem a ideia de redundância, de testes explicitamente testando a mesma regra duas vezes ou mesmo uma camada do sistema testando as regras de outra camada. Para tentar desmistificar isso devemos entender o código e as regras que sua API possui.
Testes Unitários (UT) X Testes Integrados (IT)
Considerando apenas a velocidade para criação e retorno de investimento (ROI) os testes unitários são mais atraentes que os testes integrados. Em sua maioria utilizam-se de Mocks (objetos que simulam o comportamento de objetos reais de forma controlada) e tem objetivo de validar se o trecho específico do código é utilizado na chamada de uma requisição, além de jamais falharem por motivos de massa de dados, ambiente instável ou requisitos faltantes, podendo somente apresentar falhas se o código for modificado.
Já o teste de integração é tão barato e rápido como o unitário, e traz como objetivo validar se os componentes de um sistema interagem corretamente uns com os outros, sendo eles comunicação entre banco de dados, outros micro serviços ou componentes externos. Nas questões de micro serviços isso se torna mais visível, haja vista que a transferência e troca de informações entre estes componentes é o que faz o sistema funcionar. Neste ponto é possível destacar que quanto aos mocks deve-se usar o mínimo possível, principalmente se o seu sistema for muito grande, pois dão muito trabalho e podem tornar a nossa vida bastante complicada, o que é o oposto dos testes automatizados. A geração de dados a serem utilizados no mock pode ser bastante custosa, sendo na montagem de seus objetos de requisição e de retorno, ou em uma manutenção forçada por conta de questões de atualização de contratos. Serviços externos como SOAP, REST, JMS entre outros podem ser mockados, mas se existir um ambiente confiável prefira sempre usar os serviços reais nos testes de integração.
É necessário para que estas duas camadas andem juntas entender onde está a regra. Se por exemplo uma exceção ao salvar os dados de uma pessoa é uma regra do “service”, é correto que se teste essa regra ao testar esta service, não é correto realizar este teste em uma camada superior “API”, pois esta não é uma regra desta camada.
Quebrando as regras é possível não se preocupar com redundâncias, afinal teste nunca é demais, mais perigoso é não ter teste nenhum, pensando principalmente nos fluxos alternativos, só é necessário que os testes estejam bem feitos, para não prejudicar a manutenção e os resultados dos testes.
Testes Integrados (IT) X Testes de Interface (UI)
Como já mencionamos os testes integrados e suas características acima, podemos dar enfoque aos testes de interface, apresentando de início suas maiores características… fragilidade e velocidade.
Embora o teste de interface nos encha os olhos por ser mais visível e demonstrar quase que fisicamente sua cobertura, seu grau de manutenção é infinitamente maior que os testes mencionados anteriormente, além de possuir um tempo de execução muito superior a um teste unitário ou integrado. Outro agravante ao teste de UI é que ele é o último teste a ser produzido, quando basicamente a aplicação está pronta, tendo sua manutenção gradativa ao ponto que o desenvolvimento ainda está sendo finalizado, o que causa muito retrabalho.
Sendo assim podemos destacar o seguinte cenário, o que cobre um teste de interface?
Os testes de interface provêm um fluxo de ponta a ponta de uma determinada funcionalidade, ou seja, se formos pensar a grosso modo em um fluxo de compra em um e-commerce ou um marketplace, por exemplo:
- Cliente realiza login;
- Cliente seleciona um produto;
- Cliente confirma o produto;
- Cliente escolhe meio de entrega;
- Cliente escolhe meio de pagamento;
- Cliente finaliza a compra.
Este fluxo E2E basicamente é realizado em 6 telas, as quais possuem conteúdos a serem mapeados para serem utilizados no teste automatizado, cada elemento de tela pertence a uma classe ou a um CSS ( Folha de Estilo em Cascatas), aos quais se tornam bastante delicados mediante alteração no código, caso estes elementos não possuam ID específico e único.
Porém este mesmo fluxo pode ser todo reconstruído na camada de integração, testes de ponta a ponta podem ser estruturados com requisições aos seus micro serviços e API’s, é possível afirmar que a montagem deste teste na camada de integração é mais cansativo do que na camada de interface, porém a longo prazo o retorno é um teste mais conciso e rápido.
A questão agora é… Não devo mais ter teste de UI?
Na verdade não é bem assim, com a ajuda do princípio de Pareto (também conhecido como regra do 80/20, lei dos poucos vitais ou princípio de escassez do fator) é possível decidir quais fluxos e o que automatizar na camada de UI. O princípio de Pareto afirma que, para muitos eventos, aproximadamente 80% dos efeitos vêm de 20% das causas. A nível de desenvolvimento de software pode-se identificar que os referidos 20% seriam os fluxos críticos do sistema, aos quais merecem sim estarem na automação de interface.
Logo, é importante salientar que ao testar uma camada superior, as regras que estão nas camadas inferiores entrarão em ação, mas o teste que está sendo executado deve focar apenas nas regras da camada ou objeto que está testando, e não deve focar nas regras específicas das camadas abaixo, que em teoria ele não conhece.