Image for post
Image for post
Rui Lopes Rodrigues | Test Automation Especialist Leader | everis Brasil

Estratégias de testes em uma arquitetura de microsserviços

O objetivo deste artigo é explorar, do ponto de vista da estratégia de qualidade, quais são as opções e as boas práticas quando temos a abordagem arquitetural e de desenvolvimento de software focada em dividir as aplicações em pequenos componentes independentes, que chamamos de estratégia de microsserviços. Esta nos traz uma série de novos desafios, mas também uma série de novas oportunidades. É um novo universo de necessidades e possibilidades, que não pode ser tratado com bons resultados sem uma nova visão de qualidade.

Esta nova visão não é necessária apenas por conta das características da nova abordagem técnica; esta via de regra está associada a um contexto de negócios menos tolerante a falhas e mais ávido por mudanças, que na verdade é a mola mestra que impulsiona boa parte das novas necessidades de qualidade.

Para começar, temos uma necessidade constante de mais e mais performance nas aplicações, assim como clientes cada vez menos tolerantes à espera. Isto é um ótimo sinal do sucesso das novas tecnologias e abordagens, mas coloca a régua em um nível mais alto e aumenta a responsabilidade do crivo de qualidade.

Dado que é muito comum que uma resposta a uma requisição precise passar por um conjunto de serviços que, de forma paralela ou serial, consomem tempos de processamento que serão somados no tempo de resposta de nossa requisição e recursos distribuídos, é muito importante:

1) Saber as necessidades da funcionalidade. O tempo de resposta que atende à necessidade do cliente com sucesso tem que ser conhecido para que possa ser atingido, e o trabalho para obter este número (ou estes números, quando falamos de mais de uma funcionalidade) pode e deve se iniciar em tempo de inception para que possamos iniciar o avanço em sua direção desde as primeiras ações concretas. Isto vale também para a quantidade de usuários esperada e a sua distribuição no tempo, assim como para os desafios de segurança e outras características não funcionais que são determinantes para o sucesso da nova aplicação do ponto de vista do negócio.

2) Entender a composição da resposta nos múltiplos serviços acessados e do consumo de tempo e recursos em cada um deles é importante para que possamos avaliar de forma precisa os gargalos.

3) Criar a automação dos testes de performance (e carga, e segurança, e stress…) na granularidade necessária para que possamos avaliar cada um dos serviços, executá-los de forma automática com frequência adequada e manter os resultados gerenciados e acompanhados é primordial para que tenhamos e continuemos tendo os resultados esperados. Não podemos deixar de ter em mente que os serviços são independentes e atualizáveis independentemente; nestas atualizações, podem sofrer alterações que impactam no resultado do todo, portanto acompanha-los individualmente é primordial.

Uma outra característica fundamental desta nova abordagem é a sua natureza distribuída, normalmente em um conjunto de pequenos módulos que disponibilizam interfaces sob REST e HTTP. Esta natureza aumenta a relevância da rede que permite a comunicação entre estes serviços (e suas configurações de conectividade) e da orquestração destas chamadas. Para acompanhar estes pontos de forma eficiente, devemos:

1) Desenvolver um smoke test dos serviços, para que qualquer flutuação na rede e na disponibilidade dos serviços possa ser localizada de forma rápida e efetiva. Estes testes devem garantir que o acesso aos serviços está funcional e que cada um deles está ativo, mas sem consumir muito tempo em verificações mais detalhadas. O objetivo deste conjunto de testes é saber se podemos prosseguir com os demais testes e ter um alarme rápido quando tivermos falhas básicas.

2) Desenvolver testes de contrato de cada um dos serviços, explorando os limites de entradas e saídas para cada um deles e a validação do processamento pelo qual o serviço é responsável. Estes testes devem ser desenvolvidos assim que tenhamos o contrato e, nas situações muito comuns em que seria ótimo poder fazer uso de um serviço que ainda não está pronto (seja para validar os testes, por conta de dependências de outros serviços ou de outros desenvolvimentos) a utilização de uma ferramenta de virtualização de serviços é a resposta. As ferramentas mais famosas neste campo são a Broadcomm Service Virtualization e a Micro Focus Service Virtualization, mas também há opções open source que entregam bons resultados, como a WireMock e a HoverFly.

3) Desenvolver testes de integração dos serviços, para garantir que eles, a comunicação entre eles e o orquestramento das contribuições produzidas de forma distribuída estão colaborando de forma adequada para os resultados finais. Nestes testes, é muito importante considerar que podemos ter variações nos tempos de resposta de cada um dos serviços, e sempre que possível injetar variações aleatórias dentro da faixa plausível para cada serviço. Estas variações de timing podem ocasionar problemas de sincronia, culminando em respostas incorretas.

Os testes unitários continuam sendo fundamentais quando falamos de garantir a qualidade de serviços e microsserviços. Eles são o nosso principal olhar de qualidade do ponto de vista técnico, do código, e este olhar é fundamental para a construção de aplicações resilientes e seguras. Nesta abordagem de pequenos blocos independentes, entretanto, se as responsabilidades de cada microsserviço forem granulares o suficiente, é possível que tenhamos uma sobreposição entre os testes de serviços e os testes de unidade. Por conta desta sobreposição é que começamos a ouvir falar de uma estruturação de testes mais focada nos serviços e sua integração do que nos testes unitários. Esta nova maneira de distribuir os testes está sendo chamada de “honeycomb testing”, em contraposição à pirâmide de testes. Na pirâmide, a distribuição de testes (em quantidades) se dá de acordo com a progressão dos volumes das diversas camadas de uma pirâmide. Na abordagem honeycomb (favo de mel, hexagonal) a classificação dos testes se faz de modo mais genérico (considerando apenas se são testes de implementação, da integração ou integrados) e o foco principal, e, portanto, a maior quantidade de testes, se encontra na validação da integração. Os diagramas abaixo exemplificam ambas abordagens:

Image for post
Image for post
Fonte: Autoria própria (autor)
Image for post
Image for post
Fonte: Autoria própria (autor)

Ambas abordagens são válidas, mas em cenários diferentes. A aplicação de honeycomb testing mostra maiores vantagens na situação que comentei acima, na qual os serviços têm responsabilidades bastante granulares e, portanto, as responsabilidades dos testes unitários e de serviços se aproximam bastante. Notem que, mesmo neste contexto, os testes unitários não são descartados. Na verdade, são reforçadas as suas responsabilidades de validação da implementação.

Em minha opinião, uma utilização efetiva do modelo de pirâmide neste cenário de pequenos serviços resulta em uma distribuição de testes muito parecida com a sugerida pelo modelo honeycomb, portanto os modelos não são de fato conflitantes. Minha leitura é que a abordagem honeycomb tem um viés mais “dev-based”, enquanto a abordagem de pirâmide tem uma linguagem mais “test-based”. São maneiras diferentes de falar das mesmas coisas, e a utilização da linguagem correta para o público correto vai ajudar na compreensão e na aplicação efetiva das boas práticas.

Em ambas abordagens também não são descartados os testes de user interface. Estes são, sim, do universo dos testes automatizados os mais custosos para desenvolvimento, manutenção e execução, mas são os únicos que podem avaliar o software do mesmo ponto de vista do usuário. Por isto, insubstituíveis no seu contexto de atuação. Devemos ter poucos (em comparação com os outros testes mais abaixo na pirâmide ou no hexágono), mas devemos tê-los. A análise estática de código para validação de boas práticas, a análise de segurança e a evolução de testes unitários por suporte de testes de mutação também são importantíssimas e devem ser executados, se não em todos os builds, em uma estratégia de repetição que faça sentido para a natureza da aplicação em produção e para o momento de desenvolvimento.

Testes manuais, jamais? Não. Também continuam tendo seu valor, nas situações que por alguma razão não podem ser automatizadas ou para o teste exploratório. Talvez um dia o suporte de IA venha a nos ajudar nesta frente de testes exploratórios, mas ainda não é o caso. Aliás, isto é assunto para outro artigo…

Written by

Exponential intelligence for exponential companies

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store