top of page
Foto del escritorRan Isenberg

Guía de prácticas recomendadas para pruebas Lambda y sin servidor de AWS (parte 1)


Las pruebas de software aumentan la calidad y la confiabilidad de las aplicaciones. Permiten a los desarrolladores encontrar y corregir errores de software, mitigar problemas de seguridad y simular casos de uso de usuarios reales.

Es una parte esencial del desarrollo de cualquier aplicación.


Serverless es una tecnología asombrosa, casi mágica. Las aplicaciones sin servidor, como cualquier otra aplicación, requieren pruebas. Sin embargo, las pruebas de aplicaciones sin servidor difieren de las pruebas tradicionales y plantean nuevos desafíos.


En esta publicación de blog, aprenderá por qué los servicios sin servidor presentan nuevos desafíos de prueba y mis pautas prácticas para probar servicios sin servidor y funciones de AWS Lambda que mitigan estos desafíos.


Segunda parte Te enseñaremos a escribir pruebas para tu servicio Serverless. Nos centraremos en las funciones Lambda y ofreceremos consejos y trucos, además de ejemplos de código, escribiendo pruebas para una aplicación Serverless real.


En la tercera parte , aprenderá a probar flujos controlados por eventos asincrónicos que pueden o no contener funciones Lambda y otros servicios sin servidor no basados en Lambda.

Puede encontrar aquí un proyecto de servicio sin servidor complementario que utiliza las mejores prácticas de pruebas sin servidor .

 

Tabla de contenido

 

¿Son diferentes las pruebas sin servidor?

Bueno, sí, y por mucha diferencia.

En los viejos tiempos, los desarrolladores ejecutaban el código localmente y este simulaba bastante bien el comportamiento de la aplicación. En la mayoría de los casos, era fácil ejecutar el código en el IDE, agregar puntos de interrupción y depurar. Si funcionaba localmente, se tenía mucha confianza en que funcionaría perfectamente una vez implementado en producción.

En las aplicaciones sin servidor, ya no es tan sencillo.


Perspectiva de las funciones lambda


Echemos un vistazo a las funciones Lambda y los desafíos de prueba que presentan.

Las funciones de AWS Lambda se ejecutan en la infraestructura de AWS en un entorno de contenedores efímeros y requieren numerosas configuraciones de funciones.

Estas características introducen numerosos desafíos que requieren una comprensión más profunda del servicio Lambda:

  1. Diferentes activadores de eventos: una función Lambda puede activarse mediante tres tipos de activadores de eventos (sincrónicos, asincrónicos, basados en sondeos) y se integra con muchos servicios de AWS. Cada evento tiene un esquema y tipos de datos diferentes para el sobre de metadatos y la carga útil de entrada del dominio empresarial. Más información aquí .

  2. Sin estado: las funciones Lambda se ejecutan en contenedores efímeros.

  3. Variables de entorno: las variables de entorno del IDE local son diferentes a las de las funciones Lambda configuradas. Esta discrepancia puede provocar errores en el tiempo de ejecución e incluso bloqueos.

  4. Rol: las lambdas se ejecutan con un rol diferente al de los permisos de usuario de IAM del desarrollador. Esta discrepancia hace que el código se ejecute correctamente de forma local y falle en la nube debido a configuraciones incorrectas de los permisos del rol.

  5. Configuraciones de memoria: la función Lambda se ejecuta con una RAM preconfigurada diferente a la de la máquina del desarrollador. Además, cuanto más RAM configure, mejor será el rendimiento de la CPU que AWS proporciona a la función .

  6. Las lambdas detrás de las puertas de enlace de API suelen estar protegidas por un WAF de Amazon y autorizadores como el autorizador de IAM, el autorizador de Cognito y el autorizador personalizado. Estas funcionalidades son difíciles o imposibles de simular localmente.

  7. Tiempos de espera: las funciones Lambda tienen un valor predeterminado de 3 segundos , pero puedes configurarlo en hasta 15 minutos. A medida que tu aplicación cambia, el tiempo de ejecución total de la función también puede aumentar y es posible que debas ajustar el valor del tiempo de espera.

  8. Dependencias externas: las funciones Lambda suelen empaquetarse como un archivo ZIP y cargarse en AWS. Si falta un paquete, la función fallará durante la invocación inmediatamente debido a errores de importación. Las capas Lambda son una opción para empaquetar dependencias externas. Sin embargo, pueden complicar aún más el caso de uso cuando no se utilizan correctamente. Lea más aquí .

  9. Los tipos de arquitectura Lambda (X86 o ARM64) afectan el rendimiento y el costo y, en muchos casos, son diferentes al tipo de arquitectura de CPU de la máquina de desarrollo. Esta discrepancia puede causar problemas al crear dependencias externas para el archivo ZIP o la capa de la función Lambda.

  10. Los arranques en frío, la simultaneidad aprovisionada y la simultaneidad reservada son temas avanzados que afectan el rendimiento de la aplicación, no se pueden simular localmente y son difíciles de simular a escala en AWS.

La conclusión es que no se garantiza que el código de aplicación que funciona localmente en su IDE se ejecute en el entorno de AWS, y mucho menos que funcione correctamente y como se espera.

 

Serverless es más que solo funciones Lambda

Allen Helton, AWS Serverless Hero, definió Serverless muy bien en su publicación de blog:

"Cuando digo sin servidor, generalmente me refiero a los servicios que utilizan los desarrolladores para crear aplicaciones. Algunos ejemplos son AWS Lambda, EventBridge, DynamoDB y Step Functions" - Allen Helton

Allen tiene razón. Obtienes servicios de caja negra de última generación y de primera clase que puedes integrar en tu rompecabezas de arquitectura. En mi opinión, Serverless es sinónimo de arquitectura basada en eventos construida sobre servicios administrados por AWS y, por lo general, tu objetivo es pasar un evento a través de una cadena de servicios hasta que llega a su destino y forma finales.

Como tal, la arquitectura sin servidor presenta nuevos desafíos de pruebas:

  1. No puedes probar cada pieza del rompecabezas por separado, especialmente las partes administradas por AWS (SQS, SNS, funciones Step, DynamoDB, etc.) y probablemente no necesites hacerlo. Puedes probar partes más pequeñas del rompecabezas, es decir, las funciones Lambda que escribes, y puedes probar el rompecabezas completo desde el evento inicial hasta el punto final.

  2. Configuración de seguridad: debe comprender cómo configurar correctamente los servicios de AWS Serverless y mantener las mejores prácticas de seguridad (cifrado en reposo y en tránsito, etc.).

  3. Configuración de infraestructura y resiliencia: los desarrolladores pueden modificar los recursos y su configuración; ¿cómo sabemos que los configuraron correctamente? ¿Cómo sabemos que los recursos existen incluso después del cambio?

  4. Cuotas de recursos y escalabilidad: los servicios sin servidor tienen propiedades de escalabilidad integradas. Sin embargo, en muchos casos necesitamos configurar sus límites para reducir los costos durante períodos de carga pesada y evitar límites de cuotas de recursos de AWS. Por ejemplo, cada cuenta y región de AWS tiene una cantidad máxima de lambdas simultáneas , que se comparten entre TODAS las funciones lambda. Si se implementan dos funciones lambda en la misma cuenta y región, una función puede escalar drásticamente y provocar la inactividad y la limitación de la otra función (error HTTP 429) ya que toda la cuenta alcanza la cuota simultánea máxima.

  5. Caja negra de funciones intrínsecas: ¿qué sucede si utiliza canales de EventBridge o Step Functions con funciones intrínsecas? No puede simularlas localmente. ¿Cómo puede estar seguro de que las configuró correctamente y de que funcionarán como se esperaba?


Sin embargo, a pesar de todos estos desafíos, hay luz al final del túnel.

Todo tiene solución, así que no te preocupes y sigue leyendo.

 

Objetivos de garantía de calidad y experiencia del desarrollador


Mantén la calma y prueba

El objetivo principal es probar tanto como sea posible para aumentar la confianza en la calidad de la aplicación; sin embargo, un objetivo secundario es que el desarrollador tenga la mejor experiencia de desarrollo en el dominio Serverless.

Cuanto mejor sea la experiencia, más rápido será el desarrollo.

Entonces, como desarrollador de aplicaciones sin servidor, me gustaría:

  1. Quiero probar mi código localmente en el IDE que elija y poder agregar puntos de interrupción. Quiero tener la mayor certeza posible de que mi función Lambda, que se ejecuta perfectamente de manera local, también se ejecutará perfectamente en mi cuenta de AWS.

  2. Quiero definir mi infraestructura como código (IaC) junto con el código de mi aplicación y probarlos juntos.

  3. Quiero ser independiente durante mi desarrollo y no interferir con el trabajo de otros desarrolladores que también estén trabajando en la misma aplicación.

  4. Quiero automatizar todas mis pruebas y eliminar la necesidad de realizar pruebas manuales.

 

Pautas para pruebas de AWS Serverless y Lambda


Estructura del proyecto de aplicación sin servidor

Cada repositorio de aplicaciones contendrá tres carpetas: código de servicio, carpeta de infraestructura como código (AWS CDK en este ejemplo) y carpeta de pruebas. Creo que un desarrollador sin servidor debe "ser dueño" de la infraestructura y poder definirla y comprender su arquitectura.

app.py es el punto de entrada de la aplicación CDK que implementa el código de infraestructura y carga la carpeta de servicio con las funciones Lambda.



Estructura del proyecto

Entorno local de las funciones Lambda

Queremos simular el entorno local de las funciones Lambda y las dependencias externas en el IDE. En Python, que es mi lenguaje de elección para las funciones Lambda, instalaremos todas las dependencias en un entorno virtual local.

En cuanto al administrador de dependencias, puedes elegir entre poetry y pipenv. Yo prefiero poetry porque es más rápido, por lo que todas las dependencias de las funciones residirán juntas en un único archivo .toml.

Todas las funciones Lambda del proyecto utilizan versiones de biblioteca idénticas definidas en el archivo toml. Al crear funciones Lambda con dependencias externas o capas Lambda, constrúyalas según el archivo .toml. Lea más sobre esto aquí .


Independencia de implementación del desarrollador

Queremos que nuestros desarrolladores puedan trabajar con cuentas y recursos reales de AWS sin interrumpir el trabajo de sus compañeros de trabajo.

Hay dos posibles soluciones que conozco:

  1. Cuenta de AWS por desarrollador

  2. Cuenta única para todos los desarrolladores

En la primera opción, cada desarrollador implementa su aplicación en su cuenta. Cada desarrollador tiene un entorno de pruebas con el que jugar, lo que reduce la posibilidad de alcanzar los límites de cuota de recursos. Sin embargo, tener varias cuentas aumenta la sobrecarga de administración de cuentas.

La segunda opción es tener una cuenta de AWS "dev" compartida entre todos los desarrolladores, pero cada desarrollador implementa su pila de aplicaciones (pila CloudFormation) con un prefijo de nombre de usuario, eliminando así la posibilidad de conflictos y permitiendo la completa libertad de los desarrolladores. En esta opción, hay más posibilidades de alcanzar las cuotas de recursos de AWS (en muchos casos, estos son límites "suaves" que se pueden incrementar por un costo adicional), pero es más fácil de administrar desde una perspectiva de empresa.

Elige la opción que tenga más sentido para ti.


Depuración en IDE y entradas de eventos generados

Creo que la depuración en la consola de AWS siempre debe ser el último recurso.

Toma más tiempo ya que no tiene puntos de interrupción, por lo que recurre a la depuración con impresión de registros, lo que se traduce en una mala experiencia en general.

Una mejor experiencia para el desarrollador sería escribir una prueba que llame a mi controlador de función Lambda en mi IDE, le envíe un evento predefinido (que coincida con el esquema de la integración Lambda) y verifique sus efectos secundarios y su respuesta.

Todo gestionado localmente, sencillo y rápido.


Lo mantendremos simple; no utilizaremos simuladores Lambda ni el enfoque de depuración local de SAM, ni crearemos imágenes de Docker locales, solo pruebas IDE tradicionales ('pytest' en Python) con eventos generados y puntos de interrupción locales.

Sin embargo, esto plantea la pregunta: ¿cómo se generan estos eventos? Dejaré eso para la segunda parte, que lo tratará en detalle. Sin embargo, si quieres un spoiler, mira un ejemplo aquí .


No se burle de los servicios de AWS a menos que sea necesario

La biblioteca de lemas de Python imita los servicios de AWS, lo que elimina la necesidad de implementar su aplicación o pagar por llamadas a la API en relación con los servicios de AWS. Otros lenguajes de programación tienen su propia implementación de lemas.

Sin embargo, todos ellos tienen algo en común: suenan muy bien en el papel, pero en mi experiencia, solo deberías usarlos si es necesario.


Déjame explicarte por qué: una desventaja de usar "motto" es que cuando lo usas para simular un servicio de AWS, te obliga a simular todos ellos. No puedes usar NINGUNA otra llamada API de servicios de AWS reales. Otra desventaja es que me he topado con casos en los que la respuesta de motto era diferente a la real. Y sí, "motto" también puede tener errores.

Por lo tanto, deberías utilizar "lema" en el siguiente caso de uso:

  • No es fácil simular un caso de uso específico, o necesita saber cómo se vería la respuesta. Por ejemplo, desea utilizar la API de organizaciones de AWS para enumerar todas las cuentas de la organización y desea que la organización tenga 50 cuentas en 3 jerarquías. A menos que mantenga esta organización de AWS real lista para su uso, una simulación de "lema" es la única forma de simular este caso de uso.


Depuración en IDE y API de AWS

Llamar a la API de servicios reales de AWS en el IDE: continuando con el último punto, cuando usemos el SDK de AWS ('boto' para Python) en Lambda, no lo simularemos. Quiero obtener la mayor certeza posible y usar los servicios reales de AWS durante mis sesiones de depuración y pruebas locales.

Por supuesto, este método implica un mayor costo general y se considera la principal desventaja de este método (y de la independencia de implementación del desarrollador) ya que todo su equipo de desarrollo implementará la infraestructura y utilizará llamadas API de AWS para interactuar con ella.


Serverless tiene muchos beneficios en términos de precios (en la mayoría de los casos, pagas solo por el tiempo de ejecución real en milisegundos para Lambdas) y AWS tiene un nivel gratuito, pero con el tiempo, puede sumarse.

Además, muchos recursos cuestan dinero para implementarlos; por ejemplo, KMS CMK, VPC y certificados son algunos de ellos.

Sin embargo, en el gran esquema de las cosas, el uso de API reales de forma local con un punto de interrupción y con facilidad aumenta la confianza del equipo en su trabajo, genera menos conflictos y discrepancias entre el código local y el código que se ejecuta en las cuentas de AWS y acelera el desarrollo. El costo mínimo debería hacer que valga la pena si utiliza servicios de AWS sin servidor puros.


Simular fallos de API

Aplique un parche a las llamadas de AWS cuando desee simular excepciones y errores para probar casos extremos en su código y aumentarla cobertura del código de línea .

Puede encontrar una plantilla de servicio sin servidor completamente funcional que incorpora estas pautas aquí , y su documentación aquí .

La segunda parte se centrará en esta área con ejemplos de código.


Activar un evento en su cuenta de AWS

Además de la depuración en el IDE local, también es fundamental activar la aplicación implementada en AWS y verificar que funcione de principio a fin.

Utilice casos de uso reales de clientes y active el inicio de la arquitectura basada en eventos, ya sea una llamada a la API REST, un mensaje de SNS o cualquier otro evento.

Las funciones Lambda y los recursos Serverless que implementó funcionarán juntos desde el principio hasta el final en su cuenta de AWS.

Estas pruebas son las pruebas definitivas, ya que simulan casos de uso y entradas de clientes reales en sus cuentas de AWS.


Automatizar todo

Escriba pruebas para todos los casos de uso y casos extremos del cliente. No deje nada sin revisar. No pruebe manualmente su servicio. Quiere ganar confianza en sus pruebas y empoderar a su desarrollador para que tenga más responsabilidad, mejor velocidad de desarrollo y confianza en su trabajo. Cuando tiene una buena cobertura, no tiene miedo de enviar a producción varias veces al día.

 

Continuará: Cómo escribir pruebas para una aplicación sin servidor de muestra

Ahora que tenemos las pautas básicas, las pondremos en práctica en la segunda parte de la serie, donde presento la pirámide de pruebas sin servidor junto con ejemplos de código y muchos consejos y trucos.

Pirámide de pruebas sin servidor
Pirámide de pruebas sin servidor








bottom of page