Pontos Principais
-
Uma estratégia bem sucedida para testar de microservices é gerenciar efetivamente os componentes interdependentes envolvidos. Isso pode envolver o isolamento, mocking, virtualização ou outras técnicas;
-
Características organizacionais têm impactos sobre a escolha das técnicas de testes, como: a maturidade da equipe e a velocidade requerida de mudança;
-
De uma perspectiva de negócio, há três consequências principais no uso dos testes: tempo para entrar no mercado, custos e riscos;
-
Cada técnica de teste tem vantagens e desvantagens, e sua escolha dependerá do contexto.
Este é o segundo artigo da série Testing Microservices. Consulte também: Testando microservices: 12 técnicas úteis - Parte 1.
A primeira parte desta série, "Testando microservices: 12 técnicas úteis Parte 1" explorou técnicas para gerenciamento entre as dependências dos componentes enquanto estiver testando microservices. Este artigo vai comparar as técnicas com base na maturidade da equipe, velocidade de mudança, tempo de colocação no mercado, custos e riscos.
Essa comparação é baseada na experiência dos autores em mais de 14 projetos, mas alguma coisa pode ser esquecida ou a experiência dos autores pode não refletir a sua. Então, por favor, ajude a melhorar este resumo para que os autores possam ajudar mais pessoas como uma comunidade. Por favor, comente o artigo, poste no LinkedIn ou tuíte com a tag #TestingMicroservices.
A tabela a seguir, compara as técnicas para testar microservices do ponto de vista gerencial. Um sinal de mais (+) indica impacto positivo, um sinal de menos (-) indica impacto negativo e um til (~) indica pequeno ou pouco efeito.
Técnica |
Características Organizacionais |
Consequências de usar a abordagem de testes |
|||
Maturidade da equipe |
Velocidade de mudança |
Time to market |
Custos |
Riscos |
|
1. Testar o microservice com uma instância de testes de outro microservice. |
Baixo impacto |
Baixo impacto |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. |
+ Baixo custo quando a complexidade é baixa. - Pode ficar dispendioso quando a complexidade aumenta. |
+ Reduz as chances de introduzir problemas nos mocks de testes. - Risco de não seguir a pirâmide de testes. |
2. Testar o microservice com uma instância de produção de outro microservice. |
Impacto moderado. |
Baixo impacto. |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. |
+ Baixo custo quando a complexidade é baixa. - Pode ficar dispendioso quando a complexidade aumenta. |
+ Reduz as chances de introduzir problemas nos mocks de testes. - Risco de não seguir a pirâmide de testes. - Pode mudar o estado dos sistemas em produção. ~ Difícil de simular cenários hipotéticos. |
3. Testar um microservice com dependências de terceiros. |
Impacto moderado. |
Baixo impacto. |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. |
+ Baixo custo quando a complexidade é baixa. - Pode ficar dispendioso quando a complexidade aumenta. ~ Chamadas para APIs de terceiros podem gerar custos.
|
+ Reduz as chances de introduzir problemas nos mocks de testes. - Risco de não seguir a pirâmide de testes. - Pode mudar o estado dos sistemas em produção. ~ Difícil de simular cenários hipotéticos. |
4. Testar um microservice com dependências internas de software legado (não microservice). |
Impacto moderado. |
Baixo impacto. |
+ Rápido para começar. - Atrasa o projeto à medida em que a complexidade aumenta. |
+ Baixo custo quando a complexidade é baixa. - Pode ficar dispendioso quando a complexidade aumenta. |
+ Reduz as chances de introduzir problemas nos mocks de testes. - Risco de não seguir a pirâmide de testes. - Pode mudar o estado dos sistemas em produção. ~ Difícil de simular cenários hipotéticos. |
5. Testar um microservice com dependências de hardware (não software). |
Impacto moderado. |
Baixo impacto. |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. |
~ Testar hardware pode ser caro. |
+ Ciclo rápido de feedback. |
6. Mocks (in-process ou remoto). |
Impacto moderado. |
Impacto moderado. |
~ Quantidade de tempo moderada para começar. + Reduz a complexidade. |
~ Pode precisar de esforços de desenvolvimento. |
+ Aumenta a cobertura do teste. - Pode se tornar obsoleto. |
7. Stubs (in-process ou remoto). |
Impacto moderado. |
Impacto moderado. |
~ Quantidade de tempo moderada para começar. + Reduz a complexidade. |
~ Desenvolvimento interno pode ser moderadamente dispendioso. |
+ Aumenta a cobertura do teste. - Pode se tornar obsoleto. |
8. Simulações (in-process ou remoto). |
Impacto moderado. |
Baixo impacto. |
+ Rápido para começar com simulações de prateleira. - Esforços internos podem tomar muito tempo. |
+ Simulações de prateleira podem ter bom custo-benefício. - Esforços internos podem ser dispendiosos. |
+ Cenários hipotéticos podem aumentar a cobertura de testes. - Esforços internos podem introduzir discrepâncias. |
9. Virtualização de serviço (remoto), também chamada de simulação de API ou ainda mocks de API. |
Impacto moderado. |
Baixo impacto. |
+ Produtos de prateleira ajudam a entrar no mercado rapidamente. |
+ Produtos de prateleira podem ter bom custo-benefício. ~ Produtos comerciais de prateleira pode ficar dispendiosos. |
+ Reduz o risco de cometer erros comuns. + Permite a simulação de problemas de rede. ~ Produtos open-source podem não ter contrato de suporte. ~ Serviços virtuais podem se tornar obsoletos. |
10. Banco de dados em memória |
Impacto moderado. |
Baixo impacto. |
+ Reduz o tempo de colocação no mercado quando o provisionamento de novos bancos de dados é problemático. |
+ Reduz o custo de licenciamento de bancos de dados comerciais. |
~ Bancos de dados em memória podem se comportar de forma diferente de um banco real. |
11. Container de teste |
Impacto moderado. |
Baixo impacto. |
+ Permite que a equipe avança em sua própria velocidade. + Reduz o tempo para entrar no mercado quando o provisionamento de novos ambientes é problemático. |
+ Pode reduzir o custo com licenciamento. + Pode reduzir o custo com infraestrutura. ~ Pode ter implicações nos custos de licenciamento. |
~ Containers de testes podem ter uma configuração diferente daquela da produção. |
12. Legado em uma caixa |
Impacto moderado para alto. |
Baixo impacto. |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. + Provisionamento de containers é mais rápido que provisionamento de ambientes em hardware. ~ Tempo anterior gasto para configurar os containers. - Potencial tempo para refatoração. |
+ Rápido para começar. - Atrasa o projeto à medida que a complexidade aumenta. + Provisionamento de containers é mais rápido que provisionamento de ambientes em hardware. ~ Custo anterior para configurar os containers. - Potencial tempo para refatoração. |
+ Reduz as chances de introduzir problemas nos mocks de testes. - Risco de não seguir a pirâmide de teste. |
Além das considerações na tabela anterior, as características da organização influenciam na escolha da abordagem nos testes. A maturidade da equipe referente àquela tarefa afetará a escolha. O ritmo da mudança nos requisitos do projeto do microservice ou das dependências também afeta a escolha. Por exemplo, projetos inéditos em mercados competitivos valorizam essas considerações de maneira diferente dos projetos que já estão no modo de manutenção.
As consequências do uso de uma determinada abordagem de testes são o tempo de colocação no mercado, custos, riscos e consequências adicionais.
Aqui está uma visão geral de alto nível das doze técnicas.
1. Testar o microservice com uma instância de teste de outro microservice
A maturidade da equipe tem pouco impacto, porque a equipe não precisa saber nada sobre de mocks de teste e como usá-los. É fácil testar desta forma, mesmo se começou a desenvolver e testar software a pouco tempo.
Essa técnica é adequada a qualquer velocidade de mudança. Se a velocidade é alta, a equipe ontem um feedback rápido dos problemas com a compatibilidade entre as APIs. Quando a velocidade é baixa, isso não é importante.
O tempo para colocação no mercado diminui para a maioria dos projetos à medida que a complexidade aumenta. É uma armadilha típica das equipes de software e uma fonte de dívida técnica para muitas grandes empresas. Essa técnica é fácil de começar, porque é necessário pouca infraestrutura adicional ou pouco conhecimento sobre mocks de testes.
Muitas empresas mantêm essa abordagem após o teste inicial, que resulta no rápido acúmulo de dívidas técnicas, eventualmente atrasando as equipes de desenvolvimento à medida que a complexidade do sistema que está sendo testado cresce exponencialmente com o número de seus componentes.
A maioria dos projetos precisa de uma combinação de técnicas de testes, incluindo mocks de testes, para alcançar a cobertura suficiente e conjuntos de testes estáveis - essa técnica é chamada de pirâmide de testes. É mais rápido colocar o produto no mercado com mocks de testes porque o desenvolvedor testa menos do que teria de testar se usasse outras abordagens.
Os custos podem crescer com a complexidade. Como não é necessário muita infraestrutura adicional ou conhecimento sobre mocks de testes, essa técnica não custa muito para começar. Os custos podem aumentar, no entanto, por exemplo, quando o desenvolvedor precisar de mais infraestrutura nos testes para hospedar grupos de microservices relacionados que devem ser testados juntos.
Testar uma instância de teste de uma dependência reduz a chance de introduzir problemas nos mocks. O desenvolvedor deve seguir a pirâmide de testes para produzir uma boa estratégia de desenvolvimento e teste, ou corre o risco de acabar com grandes conjuntos de testes E2E (end-to-end) que são custosas de manter e demoram para executar.
Use esta técnica com cautela somente após consideração cuidadosa da pirâmide de testes e não caia na armadilha da pirâmide de testes invertida.
2. Testar o microservice usando uma instância em produção de outro microservice
A equipe precisa tomar cuidado extra ao testar usando uma instância de produção e deve ter um nível de confiança bem alto nas equipes que trabalham com os mocks dos testes.
Os custos e o tempo de colocação no mercado não diferem da primeira técnica. A equipe está ligada ao ciclo de release da produção, o que pode atrasar os testes.
A equipe precisa tomar cuidado extra, porque os riscos dessa técnica são muito mais altos do que nos mocks. Testar conectando-se a sistemas de produção pode alterar o estado dos sistemas de produção. Use esse método apenas para APIs sem estado ou com dados de testes cuidadosamente selecionados que a equipe possa usar na produção.
Testar com uma instância de produção geralmente significa que é difícil simular cenários de falha hipotéticos e respostas a erros. Tenha isso em mente ao projetar a estratégia de desenvolvimento e teste.
Testar o desempenho de uma instância com dependência do sistema em produção pode causar um desgaste desnecessário nestes sistemas.
Essa técnica geralmente é aplicável a APIs simples, estáveis e não críticas, que é um caso de uso raro. Evite-o a menos que seja identificado um bom motivo para fazê-lo.
3. Testar um microservice com dependências de terceiros
A equipe precisa saber como configurar os dados de testes com dependências de terceiros, mas, de toda forma, não precisa ter experiência especial.
A equipe está ligada ao ciclo de release de terceiros, o que pode atrasá-los.
A organização pode ter que pagar para testar com uma API de terceiros, uma vez que terceiros normalmente cobram por transação.
4. Testar um microservice com dependências internas de software legado (não microservice)
Essa técnica oferece um feedback rápido sobre questões do contrato entre o novo mundo dos microservices e os antigos sistemas legados, reduzindo o risco.
Além de todas as deficiências da técnica 1, o desenvolvedor também precisa ter em mente que os sistemas legados geralmente têm problemas com a disponibilidade do ambiente de testes e a configuração destes ambientes.
5. Testar um microservice com dependências de hardware (não software)
A equipe precisa saber como configurar os dados dos testes na dependência do hardware.
O hardware geralmente tem um ritmo lento de mudança, mas pode ser caro. Pode custar muito para adquirir até uma única instância de hardware para ser usada apenas para fins de testes. Quando o desenvolvedor precisar de mais hardware para executar testes em paralelo por diferentes equipes ou builds/pipelines, seus custos poderão aumentar significativamente.
Da mesma forma que na técnica anterior, há um rápido retorno de feedback entre os microservices e o hardware que reduz os riscos - mas o hardware pode ter problemas com a disponibilidade do ambiente de testes e a configuração dos dados de teste.
6. Mocks (in-process ou remoto)
Mocks ajudam a reduzir a complexidade dos casos de testes e diminuem o tempo para investigar e reproduzir problemas, mas apresentam um alto risco de discrepâncias entre APIs. Eles reduzem a complexidade fazendo suposições sobre o comportamento de outros sistemas, mas podem fazer suposições incorretas ou obsoletas sobre como uma API funciona. Quanto maior o ritmo de mudança dos requisitos do projeto, mais importante é manter os mocks atualizados. Consulte por "testes de contrato" para descobrir estratégias para reduzir esse risco.
Leva algum tempo para começar a usar mocks e definir uma estratégia de mitigação, como contratos orientados ao consumidor, testes integrados ou testes de integração para garantir que os mocks permaneçam atualizados. Os mocks podem ficar desatualizados, e uma execução bem-sucedida de um conjunto de testes obsoleto fornecerá uma falsa confiança na qualidade.
Pode não haver soluções de mock gratuitas disponíveis para sua stack de tecnologias, portanto, o desenvolvedor pode ter que desenvolver uma internamente ou comprar um produto comercial.
Os mocks permitem testar uma falha de baixa granularidade e cenários hipotéticos, aumentando assim a cobertura dos testes.
Usar mocks é uma boa idéia na maioria dos casos de uso e pode fazer parte das melhores pirâmides de testes ou dos testes honeycombs. Os mocks são frequentemente uma técnica essencial para testar sistemas complexos.
7. Stubs (in-process ou remoto)
Enquanto o mock substitui um objeto, o microservice depende de um objeto específico de teste que verifica se aquele microservice está usando corretamente, um stub o substitui por um objeto específico de teste que fornece dados de testes ao microservice. As vantagens e desvantagens são semelhantes.
O desenvolvimento interno de stubs para dependências complexas pode ser demorado e caro. Escolha mocks de prateleira, simuladores ou ferramentas de virtualização de serviço sobre stubs.
8 Simuladores (in-process ou remoto)
A equipe deve saber como usar o simulador escolhido. Os simuladores geralmente apresentam formas específicas para os desenvolvedores e testadores interagirem com eles.
As empresas normalmente criam simuladores para APIs estáveis ou amplamente usadas e o desenvolvedor pode começar rapidamente a usar esses simuladores prontos para uso. Testes rápidos e antecipados reduzem o tempo de colocação no mercado e o uso de simuladores estáveis prontos para uso pode ser econômico. Eles podem fornecer uma ampla gama de respostas de erro predefinidas e cenários hipotéticos para aumentar a cobertura dos testes.
O desenvolvimento do próprio simulador para dependências complexas pode ser demorado e caro, podendo correr o risco de introduzir discrepâncias entre o simulador e a dependência real e criar falsa confiança nos testes.
É fácil, no entanto, substituir uma dependência complexa por um simulador sofisticado e esquecer que o desenvolvedor deve modernizá-lo à medida que a dependência evolui. Leve em consideração os custos de manutenção que virão.
Essa técnica permite simular problemas de rede, o que é crítico para testar arquiteturas de microservices que dependem de redes.
Escolha simuladores prontos para uso sempre que possível. Crie simuladores internos apenas quando a equipe tiver uma vasta experiência com a dependência e simulação reais.
9. Virtualização de serviço, também chamada de simulação de API ou ainda mocks de API
A equipe precisa saber como fazer a virtualização de serviços e é essencial escolher uma ferramenta que tenha tutoriais e outros materiais.
As ferramentas de virtualização de serviços ajudam a manter os serviços virtuais atualizados. Quanto mais rápido o ritmo de mudança dos requisitos do projeto, mais crítico é evitar que os serviços virtuais se tornem obsoletos. As ferramentas de virtualização de serviços fornecem técnicas e componentes, um dos quais é "gravar e reproduzir", uma técnica que permite recriar rapidamente serviços virtuais para APIs que mudam frequentemente. Consulte por "testes de contrato" para outras estratégias para reduzir esse risco.
O uso de ofertas de virtualização de serviço prontas para uso, ajuda o produto a chegar ao mercado mais rapidamente se o desenvolvedor adotar padrões bem testados. Os consultores familiarizados com as ferramentas disponíveis no mercado podem trabalhar em estreita colaboração com desenvolvedores e testadores e ajudá-los a escolher uma abordagem de testes de microservice com base na experiência de muitos projetos.
O uso de ferramentas prontas pode ser rentável quando a equipe começou a usar microservices há pouco tempo, porque o fornecedor pode ajudá-lo a evitar erros comuns. Com o tempo, no entanto, o uso de uma oferta comercial pode se tornar caro. Escolha um fornecedor com base nas projeções do ROI.
O uso de ferramentas de código aberto sem contrato de suporte pode fazer com que os desenvolvedores e testadores gastem tempo para corrigir bugs e manter a documentação e os materiais de treinamento.
A virtualização de serviços ajuda a reduzir a complexidade do sistema testado. As ferramentas ajudam a gerenciar as suposições. A maioria das ferramentas de virtualização de serviços estão no mercado há muitos anos e foram projetadas para mainframes e sistemas monolíticos. Escolha a ferramenta comercial ou de código aberto mais adequada à sua arquitetura de microservices - mas qualquer serviço virtual pode ficar desatualizado. Consulte as recomendações do fornecedor para estratégias de mitigação.
10. Banco de dados in-memory
A equipe tem que entender os riscos técnicos ao mudar os testes para utilizar um banco de dados in-memory.
Como essa técnica usa um banco de dados, o ritmo da mudança tem pouco impacto aqui. Reduz significativamente o tempo de lançamento no mercado, quando o provisionamento de novos bancos de dados para fins de desenvolvimento ou teste é problemático.
Muitos bancos de dados in-memory são de código aberto e gratuitos, o que obviamente pode ajudar a reduzir os custos de licenciamento. Mas o banco de dados in-memory pode se comportar de maneira diferente do real em casos extremos. Execute um teste em um banco de dados real como parte de sua estratégia de testes, para observar as diferenças entre os bancos de dados reais e in-memory.
11. Container de testes
A equipe tem de saber como executar containers de testes. Como os testes operam com uma dependência real, em um container, o ritmo da mudança tem pouco impacto nessa solução.
A execução de containers de testes de serviços de terceiros ou virtualização de serviços podem reduzir as dependências entre as equipes e permitir que cada equipe se mova no seu próprio ritmo. Esses containers também podem reduzir significativamente seus custos de infraestrutura de teste.
A execução de um container de testes em vez de depender de uma instância compartilhada, reduz a probabilidade de que problemas no ambiente afetem os resultados dos testes.
A execução de uma edição de desenvolvimento de um banco de dados comercial como um container de testes para fins de desenvolvimento e teste pode reduzir seus custos de licenciamento. A execução de bancos de dados comerciais de configuração de produção como um container pode ser cara.
O container de testes pode ser configurado de maneira diferente da dependência real, levando à falsa confiança no conjunto de testes. Certifique-se de configurar o banco de dados do container da mesma forma que o banco de dados de produção (por exemplo, use o mesmo nível de isolamento de transação).
12. Legado empacotado
A maturidade da equipe tem impacto moderado apenas quando o sistema legado pode ser portado para containers sem muito esforço, mas é mais complexo se a equipe precisar refatorar partes da configuração e código no sistema legado antigo para fazê-lo funcionar em um container. A quantidade de trabalho depende do projeto, portanto, primeiro pesquise e avalie o tamanho do trabalho.
A infraestrutura herdada leva tempo para ser provisionada. Após um investimento inicial potencialmente substancial na configuração do legado no container, o tempo e o dinheiro gastos para iniciar e executar novos ambientes (containers) são ordens de magnitude inferiores às configurações de hardware típicas.
Essa técnica reduz a chance de introduzir discrepâncias entre os mocks de testes e os sistemas reais. Certifique-se de configurar o sistema legado do containers da mesma forma que o sistema de produção, para que não haja discrepâncias significativas entre os ambientes de produção e teste.
Resumo
Exploramos técnicas para gerenciar dependências de microservices ao testá-los do ponto de vista de um gerente e as comparamos com base na maturidade da equipe, ritmo de mudança, tempo de mercado, custos e riscos.
As informações devem preencher algumas lacunas e ajudar a definir a estratégia de desenvolvimento e testes (incluindo a pirâmide de testes) para reduzir o tempo de comercialização, reduzir custos e aumentar a qualidade da organização.
Cada método tem suas vantagens e desvantagens, e qual opção faz sentido para o aplicativo depende do ambiente. A parte 3 deste artigo incluirá estudos de caso, que destacam como diversas empresas aplicam esses conhecimentos para tomar suas decisões.
Caso encontre algo que não esteja claro no artigo ou se tiver alguma dúvida ou preocupação específica do projeto, entre em contato com os autores: Wojciech Bulaty em wojtek@trafficparrot.com e Liam Williams em liam@trafficparrot.com.
Sobre os autores
Wojciech Bulaty é especialista no desenvolvimento de software ágil e arquitetura de testes. Ele tem mais de uma década de experiência prática em codificação e liderança em agilidade, automação, XP, TDD, BDD, pair programming e clean coding. Atualmente trabalha na Traffic Parrot, onde ele ajuda as equipes que trabalham com microservices a acelerar a entrega, melhorar a qualidade e reduzir 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 open-source e autor de várias pequenas bibliotecas. Mais recentemente, ele se juntou à equipe da Traffic Parrot, onde voltou sua atenção para o problema de melhorar a experiência de testes ao mudar para uma arquitetura moderna de microservice.
Este é o segundo artigo da série Testing Microservices. Consulte também: Testando microservices: 12 técnicas úteis - Parte 1.