top of page
  • Foto do escritorRan Isenberg

Guia para testes sem servidor e Lambda - Parte 3 - Fluxos assíncronos avançados


Assíncrono

O teste de software aumenta a qualidade e a confiabilidade do aplicativo. Ele permite que os desenvolvedores encontrem e consertem bugs de software, mitiguem problemas de segurança e simulem casos de uso de usuários reais.

É uma parte essencial do desenvolvimento de qualquer aplicativo.


Serverless é uma tecnologia incrível, quase mágica. Aplicativos serverless, como quaisquer outros aplicativos, exigem testes.

No entanto, testar aplicativos sem servidor é diferente dos testes tradicionais e apresenta novos desafios.


Nesta postagem, você aprenderá a testar fluxos assíncronos orientados a eventos que podem ou não conter funções Lambda.


Postagens anteriores da série:

  1. Parte 1 - você aprendeu por que os serviços sem servidor apresentam novos desafios de teste e minhas diretrizes práticas para testar serviços sem servidor e funções do AWS Lambda que atenuam esses desafios.

  2. Parte 2 - você aprendeu a escrever testes para seu serviço Serverless. Nós focamos em funções Lambda e fornecemos dicas e truques e exemplos de código escrevendo testes para um aplicativo Serverless real. Além disso, você aprendeu minha adaptação Serverless à pirâmide de testes e a implementou.


Um projeto de serviço Serverless complementar que utiliza as melhores práticas de teste Serverless pode ser encontrado aqui .

 

Índice

 

Recapitulação da pirâmide de testes sem servidor

No primeiro post da série, apresentei a pirâmide de testes Serverless.

Esta postagem pressupõe que você esteja familiarizado com a pirâmide de testes e entenda seus princípios.

 Pirâmide de testes sem servidor
Pirâmide de testes sem servidor

Definimos as seguintes etapas de teste:

  1. Testes unitários para nosso código de domínio de negócios de função Lambda - teste esquemas de validação de entrada e teste funções isoladas.

  2. Testes de infraestrutura para nosso código AWS CDK que afirmam as melhores práticas de segurança.

  3. Testes de integração que são executados após a implantação do serviço na AWS. Os testes são executados no IDE, chamam a função de entrada do manipulador Lambda com um evento gerado e simulam fluxos felizes e casos extremos (casos extremos são simulados com simulações).

  4. Testes de ponta a ponta que acionam todo o serviço na AWS com um evento de entrada do cliente.

 

Minha Metodologia de Teste

Nesta seção, apresentarei minha abordagem para testes sem servidor e como crio os testes necessários para microsserviços sem servidor com base na pirâmide de testes sem servidor.

Baseio minha abordagem na presença de funções Lambda no fluxo que gostaria de testar.

Funções Lambda estão incluídas

Aprendemos como testar funções Lambda nopost anterior .

Seguimos as diretrizes da pirâmide de testes e adicionamos testes de unidade, integração e ponta a ponta à nossa função Lambda.

Para os testes de integração, precisamos gerar o evento de entrada apropriado de acordo com o gatilho assíncrono do Lambda: pode ser uma lista de eventos do SQS (um lote), um evento EventBridge, um evento de fluxos do DynamoDB, etc.

Para testes de ponta a ponta, precisamos acionar a cadeia de eventos que eventualmente acionará a função Lambda em nossa conta da AWS.


Funções Lambda não estão incluídas

Vamos discutir casos de uso em que não há funções Lambda no seu microsserviço.

Alguns exemplos vêm à mente: uma máquina de estados Step Function com funções intrínsecas e pipes EventBridge que conduzem um processo ETL e enviam um evento para um barramento EventBridge.

Como você os testa? Você não pode escrever testes unitários ou de integração como fez para suas funções Lambda; não há código e ponto de entrada para disparar localmente; é tudo configuração de infraestrutura!

Você deve se perguntar: DEVO testar esses serviços gerenciados pela AWS ou focar no panorama geral: o destino do evento e os efeitos colaterais?

Minha resposta é: Sim, tudo o que podemos e DEVEMOS fazer é um teste de ponta a ponta.

Escreveremos testes de ponta a ponta, acionaremos a cadeia de eventos, validaremos seus efeitos colaterais e garantiremos que o evento chegue ao fim da estrada corretamente, conforme o esperado.


Vamos ver alguns exemplos e como testar o serviço.

 

Testando fluxos de mensagens assíncronas

SNS->SQS->Lambda
SNS->SQS->Lambda

Um fluxo puramente assíncrono orientado a eventos.

Uma função Lambda está envolvida, então escreveremos testes unitários e de integração.

Os testes de integração gerarão uma lista de registros (veja o exemplo de evento do AWS SQS), chamarão o manipulador lambda e validarão seus efeitos colaterais.


Os efeitos colaterais da função Lambda podem incluir escrever em uma tabela do DynamoDB, chamar uma API, etc. Em testes de integração, você pode simular as chamadas para esses efeitos colaterais localmente e garantir que eles sejam chamados e chamados com os parâmetros corretos.

Também é crucial neste caso garantir que a função Lambda, que recebe um evento de entrada do SQS na forma de uma lista de eventos (um lote), não gere uma exceção não capturada que faça com que todo o lote de eventos seja retornado para a fila.

Esteja ciente de que, neste caso, não podemos simular localmente quaisquer efeitos colaterais relacionados ao SQS, como:

  1. Verifique o tratamento adequado de falhas parciais.

  2. Valide se configuramos corretamente uma fila de mensagens mortas do SQS.

Portanto, esses efeitos colaterais serão testados apenas por testes E2E.


Para um fluxo feliz E2E, publique uma mensagem SNS no tópico SNS via AWS SDK e valide os efeitos colaterais da função ('colocar item' em uma tabela do DynamoDB, etc.). Outra opção é pesquisar o grupo de logs da função, filtrar pelo registro de data e hora de log esperado e verificar se a função atingiu uma mensagem de log específica que afirma que a ação ocorreu.


Para falhas E2E, certifique-se de ler toda a documentação relacionada ao serviço gerenciado.

O Amazon SQS tem documentação muito informativa sobre como lidar com falhas parciais e integração de filas de mensagens mortas.

Você pode publicar eventos malformados no tópico SNS e garantir que eles sejam enviados para a fila de mensagens mortas pré-configurada, aguardando e buscando (com um tempo limite) mensagens da fila de mensagens mortas SQS até que o evento esperado seja encontrado (o teste é aprovado) ou ocorra um tempo limite (o teste falha).

 

Testando fluxos síncronos e assíncronos

API GW -> DynamoDB -> Fluxos DynamodbDB -> Lambda
API GW -> DynamoDB -> Fluxos DynamodbDB -> Lambda

Este caso de uso contém fluxos síncronos e assíncronos: os dois primeiros são síncronos e o último é assíncrono.


Um API Gateway recebe uma solicitação POST e grava em uma tabela do DynamoDB sem uma função Lambda envolvida (usa um proxy de serviço da AWS ). A alteração da tabela do DynamoDB aciona um evento de fluxos do DynamoDB que aciona uma função Lambda.

Não é possível testar localmente no IDE o API Gateway e verificar se ele grava no DynamoDB.

Você só pode testar com um teste de ponta a ponta que enviará a solicitação POST necessária e validará o efeito colateral que aconteceu e o item foi escrito. Você pode fazer isso verificando diretamente a tabela do DynamoDB ou chamando uma API REST de item GET no API Gateway (assumindo que haja tal API).


Agora, vamos testar o fluxo assíncrono.

Uma função Lambda está envolvida para que possamos escrever testes unitários e de integração.

O teste de integrações gerará um evento de entrada com base no esquema de eventos de fluxo do DynamoDB.

Para simulação de erros, você pode injetar dados de evento de entrada inválidos, chamar o manipulador de função Lambda no IDE e garantir que ele os manipule corretamente. Você pode fazer isso simulando uma função específica de tratamento de erros e afirmando que ela foi chamada e foi chamada com os parâmetros corretos.


Para os testes de ponta a ponta, usaremos o teste para a parte síncrona. Agora, é aqui que fica complicado. Precisamos entender qual é o efeito colateral do Lambda. Não podemos usar seu código de retorno, pois ele disparou de forma assíncrona e não retorna uma resposta que possamos obter.


Precisaremos verificar seu efeito colateral. Se a função gravar na tabela do DynamoDB, usaremos um mecanismo de polling (dentro dos limites do reason e definiremos um tempo limite curto e algumas tentativas) e verificaremos a entrada do DynamoDB chamando a API get (se não houver API, usaremos o AWS SDK para olhar a tabela do DynamoDB diretamente). Este método se aplica a quaisquer outros efeitos colaterais que ele fizer.

Outra opção é consultar o grupo de log de funções, como feito no exemplo anterior, e validar se ele processou o evento corretamente.

Observe que, se o efeito colateral for complicado de validar no fluxo E2E, ele deve pelo menos ser validado nos testes de integração. Uma vez que o fluxo de teste de integração o valida, a asserção do grupo de log pode ser boa o suficiente.

 

Testando fluxos assíncronos não baseados em Lambda


SQS -> Pipes do EventBridge -> Função de Etapa -> SNS
SQS -> Pipes do EventBridge -> Função de Etapa -> SNS

A definição do pipe EventBridge:

Neste caso, temos um pipe EventBridge não baseado em Lambda:

  1. Define o evento de origem de uma fila SQS.

  2. Filtra o evento de acordo com uma configuração predefinida.

  3. Enriquece o evento com uma máquina de estados Step Function que contém apenas funções intrínsecas (sem funções Lambda envolvidas) e retorna um evento enriquecido.

  4. Envia o evento enriquecido para um tópico SNS.

Neste caso, usamos um serviço Serverless gerenciado pela AWS e escrevemos ZERO código de função Lambda. Nosso "código" é o código de configuração de infraestrutura que constrói esses recursos na AWS:

  • A máquina de estados da função degrau

  • A fila SQS

  • O tópico SNS

  • O próprio pipe do EventBridge

  • Todas as funções necessárias e a configuração que vincula os recursos

Como nenhuma função Lambda está envolvida, só podemos escrever testes de ponta a ponta.

Precisaremos escrever um teste que coloque uma mensagem na fila de entrada do SQS (que corresponda ao filtro de pipe) e observe o final da cadeia, o tópico do SNS.

Em nossa conta de ambiente de teste (não produção), adicionaremos uma fila SQS somente de teste para assinar o tópico SNS de destino. Não adicionaremos esse SQS em ambientes de produção.

Em nosso teste, buscaremos mensagens do SQS de destino de teste até que uma mensagem seja recebida ou um tempo limite seja atingido. O teste falhará se encontrarmos um tempo limite em nossa pesquisa, o que significa que a mensagem SNS não foi enviada, ou se recebermos uma mensagem SQS malformada que não corresponde a todo o esquema de mensagem enriquecida que o pipe EventBridge deveria produzir.


Outra opção para testes E2E é testar individualmente a máquina de estado da Step Function; acioná-la com uma entrada, esperar que ela termine sua execução e validar sua saída via AWS SDK API, independentemente de ter enriquecido o evento de entrada corretamente ou não. Você também deve testar casos de uso em que entradas inválidas chegam a um estado de 'falha' na máquina de estado.

Algumas observações:

  1. Embora não tenhamos escrito NENHUMA linha de código de função Lambda, escrevemos partes da lógica no código de configuração da infraestrutura, seja a etapa intrínseca da função step ou a parte do filtro de pipe do EventBridge que contém lógica de esquema de domínio de negócios.

  2. Precisamos de menos testes (sem integração ou unidade), mas acho que os testes são menos intuitivos de escrever.

  3. Podemos escrever apenas testes E2E que acionem recursos da AWS e sejam executados em nossa conta da AWS.




Comentários


bottom of page