BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos Testando microservices: 6 estudos de caso com uma combinação de técnicas de teste - Parte 3

Testando microservices: 6 estudos de caso com uma combinação de técnicas de teste - Parte 3

Pontos Principais

  • Uma consideração importante que devemos ter ao testar os microservices é como gerenciar suas dependências. Várias técnicas podem ser utilizadas para dissociar as dependências, mas todas elas possuem vantagens e desvantagens que as equipes de desenvolvimento e de controle de qualidade devem conhecer;

  • Arquitetos, desenvolvedores e equipes de controle de qualidade devem trabalhar juntos para entender e especificar as metas de teste, o contexto e as restrições;

  • Fornecer uma abordagem holística de teste geralmente requer a implementação de várias estratégias de teste. Devem ser escolhidas com cuidado para evitar retrabalho ou a criação acidental de complexidade no conjunto de testes;

  • O teste de contrato é uma abordagem valiosa para verificar as interações entre os serviços. Os testes de contrato podem ser combinados com o uso criterioso de um número limitado de testes de ponta a ponta para verificar fluxos completos de negócios;

  • Mocks e virtualizações de serviço ajudam a desacoplar os componentes durante os testes. Deve-se tomar cuidado para garantir que essa dupla permaneça correta e atualizada com a implementação associada.

Este é o terceiro artigo da série Testing Microservices. Consulte também: Testando microservices: 12 técnicas úteis - Parte 1 e Testando Microservices: tradeoffs de doze técnicas - Parte 2.


Na Traffic Parrot, trabalhamos recentemente com seis empresas que representavam um amplo espectro de domínios do setor e a maturidade na adoção de microservices. Essas empresas usaram uma combinação das técnicas de teste descritas na Parte 1 e avaliadas na Parte 2[b] desta série de artigos, que permitem gerenciar componentes dependentes durante o teste de microservices. Nesta terceira parte, apresentaremos estudos de caso que demonstram como essas seis empresas usaram essas técnicas.

Começaremos com três estudos de caso que são uma combinação de técnicas de testes aplicadas como uma solução holística. Os últimos três estudos de caso vão descrever a aplicação de uma única técnica para resolver um problema específico.

Combinação de técnicas: Startup de seguros nos EUA

Arquitetura: Microservices novos substituindo um monólito recém-construído.

Técnica da pilha: Go, Python, NodeJS, gRPC, protocol buffers, Docker, Kubernetes.

Prioridade: Entrega rápida, será feita a refatoração do processo de entrega após a primeira entrada em produção.

Técnicas de teste utilizadas:

  • Técnica # 1 - Testando o microservice com uma instância de teste de outro microservice (testes E2E);
  • Técnica # 6 - Mocks (em processo);
  • Técnica # 9 - Virtualização de serviço (por cabo e remoto);
  • Técnica # 11 - Teste container.

Gestão de contratos:

  • As equipes usam mocks da API para comunicar a sintaxe e a semântica dos contratos entre si;
  • Os mocks da API definem contratos instantâneos que são testados automaticamente para garantir que estejam atualizados com as especificações de protocolo mais recentes.

Pontos principais:

  • Foram utilizados mocks de API de protocolo gRPC para permitir que as equipes trabalhem em paralelo;
  • Foram usados testes automatizados para garantir que os mocks de API não ficassem desatualizados.

A startup tinha duas equipes trabalhando em um conjunto com três novos microservices que deveriam ser entregues em dois meses. Os microservices estavam substituindo parte de um monólito obsoleto. As equipes decidiram testar os componentes internos dos microservices Go com testes de unidade usando mocks em processo implementados com a estrutura GoMock. Eles testaram interações com o banco de dados com testes de integração em nível de componente, no qual usam um banco de dados em um teste container para evitar a dependência de uma instância compartilhada de um banco de dados de produção.

Para gerenciar contratos entre equipes e permitir que trabalhem em paralelo, eles decidiram usar mocks de API que seus produtores criaram e que foram compartilhados com os consumidores, criando assim os mocks de serviço da API gRPC usando uma ferramenta de simulação de API.

Eles também usaram alguns testes manuais do E2E em um ambiente de pré-produção para garantir que os microservices funcionassem agrupados mesmos na ausência dos testes automatizados. Além disso, preencheram as lacunas nos testes automatizados após o primeiro prazo.

Como se tratava de um projeto novo que foi construído no prazo, a empresa decidiu não fazer a versão das APIs dos microservices. Ao invés disso, disponibilizaram tudo em produção por release (geralmente chamados de releases instantâneas). Eles permitiram que o tempo de inatividade dos serviços e a degradação da experiência do cliente fossem suaves, comunicando ao clientes com antecedência. Os técnicos envolvidos começaram a versão semântica das APIs após o lançamento do primeiro produto. Isso permitiu que melhorassem o gerenciamento de alterações da API permitindo uma maior compatibilidade com as versões anteriores além de melhorar o tempo das atividades dos clientes.

Outra questão interessante que encontraram no início foi que os mocks das APIs estavam ficando depreciados todos os dias, porque as APIs mudavam diariamente. Essas mudanças geralmente não eram compatíveis com versões anteriores, pois os desenvolvedores estavam refatorando os arquivos de protocolo para refletir o modelo de domínio em rápida evolução, que ainda não haviam definido de maneira clara. Essa é uma característica comum dos projetos novos, entregues por equipes que usam uma abordagem iterativa para agregar valor aos clientes. Para cumprir os prazos, a empresa decidiu testar as simulações da API disparando uma solicitação em um microservice simulado e um real, comparando as duas respostas a uma definição de contrato de pares de request/response esperada, conforme definido em um formato personalizado, específico da empresa. Dessa maneira, os mocks da API e o serviço real tinham a certeza de que foram atualizados quando comparados com a definição mais nova do comportamento esperado, definido no arquivo do contrato.

Combinação de técnicas: Empresa espanhola de comércio eletrônico

Arquitetura: Passando de um monólito de uma década para microservices.

Pilha de tecnologia: Java, HTTP REST, gRPC, protocolos, JMS, IBM MQ, Docker, OpenShift.

Prioridade: Mudar para a abordagem API-first para permitir o trabalho paralelo e equipes desacopladas. Escalar a adoção dos microservices entre 3.000 desenvolvedores da empresa.

Técnicas de teste utilizadas:

  • Técnica # 1 - Testando o microservice com uma instância de teste de outro microservice (testes E2E);
  • Técnica # 6 - Mocks (em processo);
  • Técnica # 9 - Virtualização de serviço (por cabo e remoto);
  • Técnica # 11 - Teste container.

Gestão de contratos:

  • As equipes usam mocks de APIs para comunicar a sintaxe e a semântica dos contratos entre si;
  • Testes de API de desenvolvimento orientado a comportamento (BDD), que também verificam interações com o mock da API;
  • As APIs são projetadas para serem sempre compatíveis com versões anteriores.

Pontos principais:

  • Isso permitiu que as equipes trabalhassem em paralelo implementando uma abordagem de API-first com mocks das APIs;
  • Os desenvolvedores criaram mocks com base no OpenAPI e nas especificações de protocolo.

A empresa decidiu trocar a arquitetura monolítica para equipes e microservices mais autônomos. Como parte dessa transição, decidiram incorporar as boas práticas recomendadas, e não forçar o uso das tecnologias e soluções específicas nas equipes.

Os arquitetos foram responsáveis por reunir as técnicas, diretrizes e ferramentas a serem usadas pelos desenvolvedores, inclusive, foram os responsáveis por criar uma arquitetura que minimizasse o desperdício através da reutilização de técnicas, ferramentas e componentes.

Os desenvolvedores escreveram os testes de integração usando JUnit e TestNG. Usaram uma ferramenta para o mock das APIs para simular os componentes dependentes. Também criaram testes do Cucumber/Gherkin para a aceitação da API do BDD para capturar os requisitos de negócios (que chamaram de "testes de contrato"), usando uma imagem do Docker de microservice e outra de uma ferramenta de mock de API chamada Traffic Parrot. Os testes do BDD verificam a API do microservice e as interações com componentes dependentes, provando as interações nos mocks da API. Dessa forma, os testes do BDD verificam a solicitação e resposta da API do microservice e toda a comunicação com os componentes dependentes por meio de asserções e verificações.

A empresa usou o JMeter para criar testes de desempenho, que examinam os microservices individualmente e substituem os componentes dependentes por mocks de APIs de dependências reais, como os microservices e o antigo monólito legado. Uma das técnicas utilizadas é a configuração dos tempos de resposta nas simulações da API e a observação do impacto no aumento da latência no serviço de chamada.

Todos os testes de unidade, aceitação e desempenho foram executados em um pipeline de entrega contínua da Bamboo.

É interessante como a empresa decidiu criar os mocks das APIs. Eles fizeram isso de duas maneiras.

Se a API que um desenvolvedor deseja consumir já existir, criavam mocks da API registrando as solicitações e as respostas. Um desenvolvedor começa criando um novo teste no computador. Em seguida, executa o teste e cria os mocks das APIs e as grava. Depois, faz o commit dos testes e das simulações para o projeto do microservice no Git. Em um pipeline de controle de qualidade (um pipeline executado por commit para verificar a qualidade do produto), é iniciado um container Docker que executa a ferramenta de simulação da API e monta a definição do mock do projeto do microservice.

Se a API que o microservice consumir ainda não existir, um desenvolvedor criará as simulações de API a partir das especificações do OpenAPI para as APIs HTTP REST ou criará os mocks de API a partir de arquivos de protocolo para APIs de gRPC.

Sempre que um desenvolvedor precisa de um banco de dados Cassandra no conjunto de testes, ele executa um teste container no banco de dados. O benefício é não ter que confiar em uma cópia centralizada. Eles criaram a própria imagem do Docker com a configuração personalizada do Cassandra.

Também desenvolvem e executam os smoke tests automatizados E2E. Essa é uma das técnicas para testar contratos entre microservices e garante que grupos de microservices funcionem juntos sem problemas. A presença do conjunto de testes E2E é justificada, pois testa não apenas o lado do produtor dos contratos, que é realizado nos testes BDD, mas também o lado do consumidor e, portanto, fornece mais confiança. Os arquitetos monitoram o número de testes E2E, mantendo a complexidade do conjunto de testes em um nível que não prejudique o processo de liberação ou as atividades diárias de desenvolvimento.

Combinação de técnicas: Empresa de mídia do Reino Unido

Arquitetura: Já existem mais de 100 microservices em execução no ambiente de produção com hardware provisionado manualmente.

Pilha de tecnologia: Java, HTTP REST, Docker, Kubernetes.

Prioridade: Mover para a nuvem (cluster interno do Kubernetes). Reduzir os custos de infraestrutura e o tempo de colocar as novas versões no mercado, afastando-se do hardware gerenciado pela equipe de operações para as equipes autônomas de recursos que são lançadas em um cluster Kubernetes. Melhorar o tempo de atividade de 99,5% para 99,95%, principalmente com a introdução de versões de tempo de inatividade zero.

Técnicas de teste utilizadas:

  • Técnica # 1 - Testando o microservice com uma instância de teste de outro microservice (usando outros microservices para testes exploratórios manuais no início do ciclo);
  • Técnica # 3 - Testando um microservice com dependências de terceiros (APIs de teste de infraestrutura da mídia do Reino Unido);
  • Técnica # 5 - Testando um microservice com dependências que não são de software (hardware e hardware de rede);
  • Técnica # 6 - Mocks (em processo);
  • Técnica # 9 - Virtualização de serviço (mocks de API de serviços de terceiros e outros microservices, na rede e remota);
  • Técnica # 11 - Testes de carga (testes de carga de banco de dados Oracle, de mocks de API e de microservice dependente).

Gestão de contratos:

  • Contratos orientados ao consumidor e teste de contrato com os outros microservices no cluster;
  • Teste de integração restrita por contrato por API de terceiros;
  • Sem testes de regressão E2E;
  • Os testes da API do BDD também verificam interações com os mocks de API;
  • As APIs são compatíveis com versões anteriores e posteriores (compatibilidade de versão n±1).

Pontos principais:

  • Foram utilizados contratos orientados ao consumidor e teste de contrato orientado ao consumidor, teste da API BDD e gerenciamento de versão da API ao invés de testes E2E.

A empresa tinha uma pilha com mais de 100 microservices que foram testados principalmente com testes automatizados de BDD E2E, mas seus custos eram muito caros, porque levou um tempo significativo do desenvolvedor para escrever e depurar o conjunto de testes. Os desenvolvedores costumavam ficar frustrados porque os testes eram difíceis devido à complexidade do sistema de teste, levando a muitos pontos de falha não determinísticos. Esses testes os impediam de entregar novos recursos sob demanda, pois levavam algumas horas para serem executados. Foi então quer perceberam que o complexo conjunto de testes levaria muito tempo e custaria muito para ser abandonado. Para mais detalhes sobre os problemas de teste E2E, podemos dar uma olhada no "End-to-End Testing Considered Harmful", de Steve Smith.

Com essa experiência, a empresa decidiu evitar os testes E2E colocando em seu lugar o novo produto em que estavam trabalhando. Este produto seria executado em um novo cluster Kubernetes interno e usaria diferentes técnicas de gerenciamento de contratos com o mínimo de teste E2E.

A principal maneira de aumentar a confiança nos contratos entre os novos microservices e o comportamento do produto como um todo era projetar contratos usando a orientação ao consumidor. A empresa escolheu testes de contrato orientados ao consumidor com o Pact-JVM para testar esses contratos. A maioria da equipe era totalmente nova em contratos voltados ao consumidor, mas conseguiram se adequar rapidamente.

Outra técnica usada para melhorar os microservices foi ter um testador manual em cada equipe de recursos. O testador executava testes manuais exploratórios de cada nova história do usuário. Executavam o microservice usando um teste container do Docker em seu computador, às vezes junto com outros microservices.

Os desenvolvedores decidiram implementar alguns dos microservices com a arquitetura limpa em mente, o que exigiu o uso de mocks no processo, usando neste caso o Mockito.

Os mocks de API executadas como teste container do Docker foram usados extensivamente para mockar o hardware de rede de terceiros e outros microservices da pilha.

Os testes de aceitação do BDD usaram o WireMock para simulação de API durante a execução nas compilações do TeamCity. Os testadores manuais usaram uma ferramenta de simulação de API que tinha uma interface com o usuário da web para os testes exploratórios. Isso facilitou a configuração de cenários de teste e os microservices.

Problema específico resolvido: Empresa ferroviária dos EUA

Problema: Mudar para uma nova infraestrutura de pipeline de CI/CD para equipes autônomas exigia uma ferramenta de virtualização de serviço que pudesse ser executada dentro dos pipelines ao invés de usar um ambiente compartilhado.

Técnica usada para solucionar o problema: Técnica #11 - Teste container (executando mocks de API como teste container do Docker)

Pontos principais: Foi utilizado teste container do Docker com mocks de API sob demanda para evitar a dependência da infraestrutura de virtualização de serviço compartilhado.

Esta empresa decidiu mudar de uma arquitetura monolítica para uma de microservice. Uma das principais mudanças que foi promovida pela empresa como parte da reestruturação, foi uma nova infraestrutura de pipeline de CI/CD.

O arquiteto responsável por projetar a arquitetura do pipeline queria usar a virtualização de serviço implantada em um ambiente compartilhado. O motivo disso foi que a empresa já possuía uma solução como essa. Os serviços virtuais estavam sendo compartilhados entre as equipes e os builds de CI/CD na arquitetura monolítica existente.

Após uma análise cuidadosa, o arquiteto percebeu que o uso de um ambiente de virtualização de serviço compartilhado por vários pipelines, desenvolvedores e testadores no novo mundo dos microservices seria contraproducente. Um dos motivos pelos quais a empresa estava migrando para os microservices era para permitir que as equipes de recursos trabalhassem independentemente umas das outras. Confiar em um ambiente compartilhado de virtualização de serviço gerenciado por uma equipe centralizada de administradores não os ajudaria a atingir esse objetivo. Além disso, qualquer ambiente compartilhado é um ponto único de falha, algo que desejavam evitar.

O arquiteto decidiu que, ao invés de um ambiente de virtualização de serviço compartilhado, usariam mocks de API que seriam implementadas como parte dos trabalhos de construção, por isso, projetou uma abordagem de implantação totalmente distribuída, na qual os mocks de API são implantados conforme necessário. Um build do Jenkins iniciaria os containers de teste do Docker com os mocks de API antes do conjunto de testes e executaria no OpenShift. Esses containers do Docker seriam derrubados após a conclusão da compilação.

Problema específico resolvido: Startup israelense de comércio eletrônico

Problema: Introduzir testes automatizados de integração de API e de terceiros em um ambiente em que os desenvolvedores ainda não estão trabalhando.

Técnica usada para solucionar o problema: Técnica #9 - Virtualização de serviço (por cabo/remoto com serviços virtuais de API de terceiros apoiados por um banco de dados, usando uma ferramenta de virtualização de serviço pronta para uso).

Ponto principal: Foi utilizado uma ferramenta de virtualização de serviços de API de terceiros para criar serviços virtuais apoiados por um banco de dados para acelerar a integração dos desenvolvedores que eram novos nos testes de integração automatizados.

A startup estava lançando um novo produto no mercado. Os desenvolvedores estavam adicionando novos recursos, mas não estavam fazendo uma API automatizada ou testes de integração de terceiros. Eles tiveram que lançar novos recursos rapidamente, portanto não havia muito espaço para alterar o processo de desenvolvimento existente.

O líder de automação do controle de qualidade desenvolveu uma API e uma estrutura de teste de integração no Jest. Com uma ferramenta comercial de virtualização de serviços pronta para uso que já havia usado em outros projetos, criou serviços virtuais que substituíram as APIs de terceiros.

A ferramenta foi implantada em um ambiente compartilhado, pois acreditava que isso lhe permitiria ter mais controle sobre a adoção da nova abordagem de teste. Cada um dos serviços virtuais individuais era apoiado por uma tabela do banco de dados que continha dados de mapeamento de solicitação HTTP para resposta. Ele decidiu permitir que os serviços virtuais fossem configurados por meio de um banco de dados, pois os desenvolvedores já estavam acostumados a configurar dados de teste no banco de dados, por isso, escolheu o MongoDB, com o qual os desenvolvedores já estavam familiarizados.

Este foi o primeiro passo na introdução de qualquer tipo de API automatizada e testes de integração para desenvolvedores dessa startup. O líder acreditava que os desenvolvedores entenderiam facilmente os serviços virtuais orientados a banco de dados. Algumas horas de integração por pessoa foram suficientes para permitir que os desenvolvedores começassem a escrever seus primeiros testes de integração automatizados.

Problema específico resolvido: Revendedor de mercadorias nos EUA

Problema: A introdução de filas do Amazon Simple Queue Service (SQS) na pilha de tecnologia resultou em problemas nos testes manuais ao verificar se as mensagens corretas foram enviadas para as filas corretas. Também bloqueou os esforços dos testes automatizados.

Técnica usada para solucionar o problema: Técnica #8 - Virtualização de serviço (por cabo/remoto com um simulador Amazon SQS).

Ponto principal: Foi usado o simulador da Amazon SQS para permitir os testes sem acesso a uma instância real do SQS.

A empresa introduziu os componentes do Amazon AWS em sua arquitetura. Infelizmente, as equipes de desenvolvimento e teste eram desconectadas na empresa, portanto, as equipes de teste trabalharam manualmente e com o mínimo de ajuda das equipes de desenvolvimento. Isso significava que a equipe de teste não tinha acesso a ferramentas que os ajudariam a testar o produto, por isso, estavam sempre atrás da equipe de desenvolvimento, com muita pressão devido ao cronograma apertado, tendo que trabalhar vários finais de semana para entregar o projeto no prazo. Além disso, foram convidados a introduzir os testes automatizados para começar lentamente a se afastar dos testes de regressão manual.

Um dos desafios técnicos era testar as integrações manuais e automáticas com uma fila do Amazon SQS. Para fazer isso, usaram um simulador Amazon SQS com uma interface de usuário, o que lhes permitiu continuar o teste manual simulando filas SQS com estado. Usaram a interface do usuário do simulador para inspecionar as mensagens na fila para verificação manual das mensagens de solicitação. Também lhes permitiu começar a introduzir testes automatizados que se integravam ao SQS usando as APIs do simulador de SQS.

Próximos passos

Os estudos de caso descritos aqui são apenas relatos parciais do que aconteceu nessas empresas. Focamos em como as equipes gerenciavam os componentes dependentes durante o teste e escolhemos especificamente esses seis estudos de caso, pois representam abordagens bem diferentes. Eles mostram como as equipes usam técnicas diferentes, dependendo do contexto e da maturidade relevante da tarefa de uma equipe.

Gostaríamos de receber feedbacks e histórias dos leitores. Quais usos das técnicas mencionadas nas partes 1 e 2 já viram? Também seria ótimo saber se concordam ou discordam de como essas empresas na Parte 3 abordaram os testes e escolheram as técnicas que foram utilizadas.

Deixe os comentários aqui no artigo ou entre em contato conosco pelo LinkedIn ou Twitter.

Se tiver alguma dúvida específica sobre o projeto, entre em contato com os autores: CEO Wojciech Bulaty em wojtek@trafficparrot.com ou @WojciechBulaty e o líder técnico Liam Williams em liam@trafficparrot.com ou @theangrydev_.

Sobre os autores

Wojciech Bulaty é especializado no desenvolvimento ágil de software e arquitetura de testes. Ele traz mais de uma década de experiência prática em codificação e liderança na escrita sobre agilidade, automação, XP, TDD, BDD, programação em pares e codificação limpa. Seu trabalho mais recente foi na Traffic Parrot, onde ajuda as equipes que trabalham com microservices a acelerar a entrega, melhorando a qualidade e reduzindo o tempo de lançamento no mercado, fornecendo uma ferramenta para simulação de API e virtualização de serviços.

Liam Williams é um especialista em automação com foco na melhoria de processos manuais propensos a erros com soluções de software de alta qualidade. Ele é colaborador de projetos opensource e autor de várias pequenas bibliotecas. Recentemente, se juntou à equipe da Traffic Parrot, onde voltou a atenção para o problema de melhorar a experiência de teste ao mudar para uma arquitetura moderna de microservice.


Este é o terceiro artigo da série Testing Microservices. Consulte também: Testando microservices: 12 técnicas úteis - Parte 1 e Testando Microservices: tradeoffs de doze técnicas - Parte 2.

 

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT