Crie uma conta gratuita ou Faça login
Podcast
Tech Leadership Rocks
Episódio 243

Como testar microsserviços com Elias Nogueira

• 52 minutos

Neste episódio, Edu Matos conversa com Elias Nogueira as nuances dos testes em arquiteturas baseadas em microsserviços, além dos desafios de testar quando há assincronismo ou dependências fora do controle do time. Elias também aponta boas práticas para testes em sistemas legados e sistemas monolíticos.

Reaja nos momentos marcantes
Curti
Boa ideia
Amei
Engraçado
Parabéns
Mind blown

Qualidade de software não termina no desenvolvimento. Se quem foca em qualidade não olha para os dados de produção, algo está errado.

— Elias Nogueira

Capítulos

00:00 Introdução
00:25 Quem é Elias Nogueira
01:31 Diferenças entre testar monolitos e microsserviços
05:07 Por onde começar a testar uma sistema legado
10:31 No que prestar atenção eo testar microsserviços
15:32 Testes de contrato vs Testes end-to-end
21:45 Dependência de serviços externos
25:38 Erros comuns em testes de microsserviços
30:16 Qualidade não se limita a testes
31:51 Testando quando há regras de negócio no banco de dados
34:40 Como testar quando há assincronismo
42:05 Gestão de dados nos testes
47:09 Como saber se minha base de testes é boa
50:57 Mensagem final

Resumo deste episódio

Diferenças entre testar monolitos e sistemas distribuídos

Em sistemas modernos, uma arquitetura distribuída de microsserviços pode ser mais fácil de testar devido à possibilidade de isolar componentes e utilizar ambientes efêmeros. Essa abordagem permite replicar a infraestrutura de forma flexível, executando apenas os serviços necessários para determinados testes.

Nos monolitos, a gestão de ambientes torna-se mais complexa. É comum existirem ambientes de desenvolvimento, QA e pré-produção espelhados de produção. Alterações em dados compartilhados ou deploys não coordenados podem causar falhas inesperadas nos testes, exigindo maior comunicação e orquestração entre times.

Alguns tipos de teste, como performance e segurança, podem ser mais simples em monolitos, onde todo o sistema está disponível para análise. Já em microsserviços, testes funcionais tornam-se mais eficientes devido ao isolamento natural dos componentes.

Estratégias para testar aplicações legadas

Migrar aplicações legadas sem testes requer uma mudança de mentalidade. Desenvolvedores acostumados com sistemas em tecnologias legadas, como Cobol, onde testes automatizados são raros, precisam adaptar-se a práticas modernas de desenvolvimento.

A principal vantagem de introduzir testes em aplicações legadas está na capacidade de experimentação segura durante mudanças. Os testes permitem validar modificações sem comprometer funcionalidades existentes, além de revelar erros antigos que passavam despercebidos.

Esse processo de migração e introdução de testes é naturalmente custoso, pois envolve não apenas traduzir requisitos, mas descobrir e documentar comportamentos implícitos do sistema original.

Prioridades ao testar sistemas distribuídos

Em sistemas distribuídos, dois focos são essenciais: garantir que cada time tenha testes adequados para seu microserviço e pensar como usuário final para validar fluxos completos.

A observabilidade é crucial aqui. Analisar logs e métricas de produção ajuda a identificar os principais caminhos que os usuários percorrem diariamente. Esses fluxos prioritários devem ser testados de forma integrada, validando não apenas o comportamento individual de cada serviço, mas também a correta comunicação entre eles.

Testes de contrato vs testes end-to-end

A necessidade de testes de contrato depende fundamentalmente da governança de APIs. Quando há controle sobre as APIs e boa gestão de versionamento (com breaking changes adequadamente versionados), testes end-to-end podem ser suficientes.

Já para integrações com sistemas externos onde não há controle sobre as APIs, testes de contrato tornam-se essenciais para garantir que mudanças não quebrem a integração.

Uma governança eficiente de APIs deve incluir não apenas versionamento, mas políticas claras de descontinuação (deprecation) e migração, com calendários e comunicação bem definidos.

Abordagens para teste de integração que envolve sistemas de terceiros

Para serviços externos, existem três abordagens principais:

  1. Mocking tradicional: Útil para desenvolvimento individual, mas não escala bem quando múltiplos times dependem do mesmo serviço externo.

  2. Virtualização de serviços: Criar mocks persistentes compartilhados entre times, facilitando atualizações centralizadas.

  3. Ambientes de sandbox: Quando disponíveis, permitem testes contra instâncias reais dos serviços externos.

O mocking deve ser usado com cautela, pois pode esconder problemas de integração reais. Vistualização de serviços oferece um bom equilíbrio entre isolamento e realismo.

Erros comuns ao testar microsserviços

  • Não implementar testes de integração adequados.
  • Testar apenas o "caminho feliz" sem considerar fluxos alternativos e casos de erro.
  • Negligenciar testes não-funcionais, especialmente performance e segurança.
  • Não considerar a observabilidade e logging durante os testes.

Testes de segurança e performance são particularmente importantes em microsserviços, onde problemas podem não afetar a funcionalidade imediata, mas impactar significativamente a experiência do usuário.

Lidando com lógica de banco de dados em testes

Quando há lógica complexa no banco de dados (como triggers e procedures), a replicação do ambiente é geralmente necessária para testes realistas. O custo de isolar adequadamente esses componentes é menor que o custo de resolver problemas em produção.

Ao longo do tempo, é recomendável reduzir a dependência de lógica complexa no banco, migrando-a para a camada de aplicação onde pode ser mais facilmente testada.

Testando comportamentos assíncronos

Sistemas distribuídos frequentemente envolvem operações assíncronas (como filas e tarefas agendadas). Para testar esses cenários, é recomendável usar bibliotecas especializadas (como Awaitility para Java) que fazem polling inteligente em vez de waits fixos.

Ferramentas assim permitem verificar a conclusão de operações assíncronas de forma eficiente, com timeouts configuráveis baseados em tempos reais de produção.

Gestão de dados para testes

A gestão adequada de dados de teste inclui:

  • Usar bibliotecas para geração de dados realistas (como DataFaker.)
  • Criar dados específicos para cada teste, não dependendo de dados existentes.
  • Garantir que os dados reflitam condições realistas do domínio.
  • Limpar dados após os testes para manter o isolamento.

Em testes end-to-end, é particularmente importante criar os dados necessários como pré-condição do teste, garantindo que os testes não dependam de estado compartilhado.

Avaliando a qualidade da suíte de testes

Uma base de testes de qualidade deve:

  • Falhar de forma informativa, com logs que facilitem o debugging.
  • Coletar métricas sobre falhas para identificar padrões e áreas problemáticas.
  • Incluir testes de mutação para validar a efetividade dos testes.
  • Ser complementada com observabilidade de produção para identificar gaps de cobertura.

Testes devem falhar durante o desenvolvimento - isso é normal e desejável. O importante é aprender com cada falha e melhorar continuamente a suíte de testes.

Conclusão

Testar sistemas distribuídos exige abordagens diferentes das usadas em aplicações monolíticas. O isolamento natural dos microsserviços facilita alguns tipos de teste, mas introduz complexidades na integração e comportamentos assíncronos.

Independentemente das técnicas específicas utilizadas, o importante é começar a testar e evoluir continuamente as estratégias. Qualquer teste é melhor que nenhum teste, e a melhoria contínua é fundamental para garantir a qualidade em sistemas distribuídos complexos.

Para ler todo o resumo Crie uma conta grátis ou Faça login