preloader

Simplifiez vos tests AWS Lambdas avec Pytest et MotoBlog

post-thumb

Auteur Atyos / publié le 28 Jan 2024

Lorsque vous travaillez avec des technologies cloud, vous vous retrouvez souvent confrontés à un dilemme lors de la mise en place de tests. Comment pouvez-vous interagir avec des services distants sans déployer un environnement complet qui pourrait alourdir vos coûts ? La réponse traditionnelle serait d’utiliser des mocks, mais avec plus de 200 services proposés par AWS, ne serait-il pas plus judicieux d’utiliser une bibliothèque qui effectue déjà le travail pour vous ? C’est là qu’intervient Moto

Moto est une bibliothèque qui simplifie grandement la création de mocks pour vos tests basés sur l’infrastructure AWS.

Dans cet article, nous allons explorer comment mettre en place des tests pour vos fonctions AWS Lambdas en utilisant Pytest et Moto.

Prérequis

Pour commencer, nous devons installer deux bibliothèques essentielles : Pytest et Moto. Vous pouvez le faire en utilisant pip :

pip install pytest
pip install moto

Pour la suite de cet article, nous supposerons que vous avez un dossier nommé tests à la racine de votre projet.

Mise en place des fixtures

Une fois les bibliothèques installées et le dossier tests créé, nous allons maintenant écrire nos premières fixtures. Si vous n’êtes pas familier avec le concept de fixtures, je vous invite à consulter la documentation.

Tout d’abord, pour éviter toute interaction accidentelle avec un environnement AWS distant, il est crucial de surcharger les variables d’environnement liées à AWS. Pour ce faire, nous allons mettre en place une configuration globale exécutée avant et après chaque test, grâce à Pytest.

# conftest.py

import pytest

monkey_patch = pytest.MonkeyPatch()

def pytest_runtest_setup():
    """Remplace les variables d'environnement liées à AWS pour éviter les appels aux services AWS pendant les tests"""
    monkey_patch.setenv('AWS_ACCESS_KEY_ID', 'testing')
    monkey_patch.setenv('AWS_SECRET_ACCESS_KEY', 'testing')
    monkey_patch.setenv('AWS_SECURITY_TOKEN', 'testing')
    monkey_patch.setenv('AWS_SESSION_TOKEN', 'testing')
    monkey_patch.setenv('AWS_DEFAULT_REGION', 'eu-west-1')
    monkey_patch.setenv('AWS_REGION', 'eu-west-1')

def pytest_runtest_teardown():
    """Restaure les variables d'environnement AWS d'origine après les tests"""
    monkey_patch.delenv('AWS_ACCESS_KEY_ID')
    monkey_patch.delenv('AWS_SECRET_ACCESS_KEY')
    monkey_patch.delenv('AWS_SECURITY_TOKEN')
    monkey_patch.delenv('AWS_SESSION_TOKEN')
    monkey_patch.delenv('AWS_DEFAULT_REGION')
    monkey_patch.delenv('AWS_REGION')

Maintenant que nous sommes sûrs qu’aucune requête ne sera transmise à AWS, nous pouvons passer à la définition des mocks pour les services AWS à l’aide de fixtures. Voici un exemple de fixtures pour Amazon S3 et DynamoDB qui renverront des mocks de ces services respectifs.

# conftest.py

import boto3
import pytest
from moto import mock_s3

@pytest.fixture()
def s3_client():
    """Mock s3 client"""
    with mock_s3():
        yield boto3.client("s3")

@pytest.fixture()
def dynamodb_client():
    """Mock DynamoDB client"""
    with mock_dynamodb():
        yield boto3.client("dynamodb")

Écriture des tests

Maintenant que nous avons mis en place nos fixtures pour Amazon S3 et DynamoDB, nous pouvons écrire nos tests. Expliquons comment utiliser ces fixtures pour écrire des tests efficaces pour vos fonctions Lambdas. Voici un exemple simple de test pour une fonction Lambda qui interagit avec Amazon DynamoDB en utilisant la fixture dynamodb_client :

# test_lambda.py

from importlib import import_module 
from dataclasses import dataclass

import pytest

@pytest.fixture()
def my_lambda():
	yield import_module("my_lambda")

@pytest.fixture()
def lambda_context(): 
    @dataclass 
    class LambdaContext: 
        function_name: str = "test" 
        memory_limit_in_mb: int = 128 
        invoked_function_arn: str = ( 
            "arn:aws:lambda:eu-west-1:123456789012:function:test" 
        ) 
        aws_request_id: str = "da658bd3-2d6f-4e7b-8ec2-937234644fdc"
        
    return LambdaContext()

def test_lambda_with_dynamodb_interaction(dynamodb_client, my_lambda, lambda_context):
    # Code de test pour une fonction Lambda qui interagit avec DynamoDB
    dynamodb_client.create_table(
        TableName='my_table',
        KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}],
        AttributeDefinitions=[{'AttributeName': 'id', 'AttributeType': 'N'}],
        ProvisionedThroughput={'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5}
    )

    # Exécutez votre fonction Lambda ici
    event = {}
    my_lambda.handler(event, lambda_context)

    # Assurez-vous de vérifier les résultats attendus de votre fonction Lambda
    assert True  # Remplacez ceci par votre propre assertion

De manière similaire, vous pouvez écrire des tests pour vos fonctions Lambdas qui interagissent avec S3 en utilisant la fixture s3_client.

En conclusion

En utilisant Pytest et Moto, vous pouvez simplifier considérablement le processus de test de vos fonctions AWS Lambdas. Les fixtures que nous avons mises en place vous permettent de simuler les interactions avec les services AWS sans avoir besoin de dépenser des ressources réelles. Cela vous aide à développer et à déboguer vos fonctions Lambdas plus rapidement et de manière plus fiable.

Avec cette approche, vous pouvez avoir confiance dans le comportement de vos fonctions Lambda sans craindre de coûts inattendus liés aux tests dans votre environnement AWS réel.

Ressources supplémentaires

Partager