[PYTHON] [AWS] Lassen Sie uns einen Komponententest der Lambda-Funktion in der lokalen Umgebung durchführen

Annahme

Dieses Mal möchte ich die folgenden Annahmen überprüfen.

Wenn Sie SAM verwenden, können Sie DynamoDB usw. in einer pseudolokalen Umgebung mithilfe der Docker-Umgebung erstellen. Dieses Mal möchte ich den Test jedoch mit Blick auf den Komponententest überprüfen (zukünftiger automatischer Test). Ich denke.

Projekterstellung

Erstellen Sie also zunächst ein Projekt. Wenn Sie sich nicht sicher sind, ob Sie ein Projekt mit SAM erstellen möchten, tun Sie dies bitte im Voraus.

Wir empfehlen Ihnen, durchzulesen.

$ sam init --runtime=python3.8
Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1

Project name [sam-app]:

Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git

AWS quick start application templates:
	1 - Hello World Example
	2 - EventBridge Hello World
	3 - EventBridge App from scratch (100+ Event Schemas)
	4 - Step Functions Sample App (Stock Trader)
	5 - Elastic File System Sample App
Template selection: 1

-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: python3.8
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./sam-app/README.md

Installation der erforderlichen Pakete

Installieren Sie die Python-Pakete, die zum Ausführen des Komponententests erforderlich sind.

$ pipenv install pytest pytest-mock mocker moto --dev

Gerätetest

Sie können die Lamnda-Funktionen mit den folgenden Befehlen aufrufen, um einen Komponententest für jede Lambda-Funktion durchzuführen. Lassen Sie uns zunächst einen Test der standardmäßig erstellten Lambda-Funktion von HelloWorld ausführen (dieser Testcode wird ebenfalls standardmäßig erstellt).

$ python -m pytest tests
============================= test session starts ==============================
platform darwin -- Python 3.8.5, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /Users/******/aws/github/sam-app
plugins: mock-3.3.0
collected 1 item

tests/unit/test_handler.py .                                             [100%]

============================== 1 passed in 0.02s ===============================

Sie können sehen, dass ein Test erfolgreich war.

Fügen Sie den DynamoDB-Zugangscode hinzu

Da der Zweck nur für Unit-Tests besteht, nehmen wir diesmal nur die für den Test erforderlichen Änderungen vor, ohne die SAM-Einstellungen zu ändern. Fügen wir nun einen Prozess hinzu, um auf DynamoDB zuzugreifen (einen Datensatz hinzuzufügen).

hello_world/app.py


import json
import boto3
import os
from datetime import datetime

def lambda_handler(event, context):
    try:
        event_body = json.loads(event["body"])
        dynamodb = boto3.resource("dynamodb")

        table = dynamodb.Table("Demo")
        table.put_item(
            Item={
                "Key": event_body["test"],
                "CreateDate": datetime.utcnow().isoformat()
            }
        )

        return {
            "statusCode": 200,
            "body": json.dumps({
                "message": "hello world",
            }),
        }
    except Exception as e:
        return {
            "statusCode": 500,
            "body": json.dumps({
                "message": e.args
            }),
    }

DynamoDB-Modell zum Testcode hinzugefügt

tests/unit/test_handler.py


import boto3
import json
import pytest
from hello_world import app
from moto import mock_dynamodb2

@pytest.fixture()
def apigw_event():
    """ Generates API GW Event"""

    return {
        "body": '{ "test": "body"}',
        "resource": "/{proxy+}",
        "requestContext": {
            "resourceId": "123456",
            "apiId": "1234567890",
            "resourcePath": "/{proxy+}",
            "httpMethod": "POST",
            "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
            "accountId": "123456789012",
            "identity": {
                "apiKey": "",
                "userArn": "",
                "cognitoAuthenticationType": "",
                "caller": "",
                "userAgent": "Custom User Agent String",
                "user": "",
                "cognitoIdentityPoolId": "",
                "cognitoIdentityId": "",
                "cognitoAuthenticationProvider": "",
                "sourceIp": "127.0.0.1",
                "accountId": "",
            },
            "stage": "prod",
        },
        "queryStringParameters": {"foo": "bar"},
        "headers": {
            "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
            "Accept-Language": "en-US,en;q=0.8",
            "CloudFront-Is-Desktop-Viewer": "true",
            "CloudFront-Is-SmartTV-Viewer": "false",
            "CloudFront-Is-Mobile-Viewer": "false",
            "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
            "CloudFront-Viewer-Country": "US",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
            "Upgrade-Insecure-Requests": "1",
            "X-Forwarded-Port": "443",
            "Host": "1234567890.execute-api.us-east-1.amazonaws.com",
            "X-Forwarded-Proto": "https",
            "X-Amz-Cf-Id": "aaaaaaaaaae3VYQb9jd-nvCd-de396Uhbp027Y2JvkCPNLmGJHqlaA==",
            "CloudFront-Is-Tablet-Viewer": "false",
            "Cache-Control": "max-age=0",
            "User-Agent": "Custom User Agent String",
            "CloudFront-Forwarded-Proto": "https",
            "Accept-Encoding": "gzip, deflate, sdch",
        },
        "pathParameters": {"proxy": "/examplepath"},
        "httpMethod": "POST",
        "stageVariables": {"baz": "qux"},
        "path": "/examplepath",
    }

@mock_dynamodb2
def test_lambda_handler(apigw_event, mocker):
    dynamodb = boto3.resource('dynamodb')
    dynamodb.create_table(
        TableName='Demo',
        KeySchema=[
            {
                'AttributeName': 'Key',
                'KeyType': 'HASH'
            },
            {
                'AttributeName': 'CreateDate',
                'KeyType': 'RANGE'
            }
        ],
        AttributeDefinitions=[
            {
                'AttributeName': 'Key',
                'AttributeType': 'S'
            },
            {
                'AttributeName': 'CreateDate',
                'AttributeType': 'S'
            }
        ],
        ProvisionedThroughput={
            'ReadCapacityUnits': 10,
            'WriteCapacityUnits': 10
        }
    )

    ret = app.lambda_handler(apigw_event, "")
    data = json.loads(ret["body"])

    assert ret["statusCode"] == 200
    assert "message" in ret["body"]
    assert data["message"] == "hello world"
    # assert "location" in data.dict_keys()

Die Hauptkorrekturen sind

ist.

Unit-Test-Ausführung

Lassen Sie uns jetzt sofort den Komponententest ausführen.

$ python -m pytest tests
============================= test session starts ==============================
platform darwin -- Python 3.8.5, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /Users/******/aws/github/sam-app
plugins: mock-3.3.0
collected 1 item

tests/unit/test_handler.py .                                             [100%]

=============================== warnings summary ===============================
[pytest]
/Users/******/.local/share/virtualenvs/sam-app-3Tr4jFKA/lib/python3.8/site-packages/boto/plugin.py:40
  /Users/******/.local/share/virtualenvs/sam-app-3Tr4jFKA/lib/python3.8/site-packages/boto/plugin.py:40: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
    import imp

/Users/******/.local/share/virtualenvs/sam-app-3Tr4jFKA/lib/python3.8/site-packages/moto/cloudformation/parsing.py:407
  /Users/******/.local/share/virtualenvs/sam-app-3Tr4jFKA/lib/python3.8/site-packages/moto/cloudformation/parsing.py:407: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working
    class ResourceMap(collections.Mapping):

-- Docs: https://docs.pytest.org/en/stable/warnings.html

Es war erfolgreich, aber ich bekomme eine Warnung. Dies bedeutet, dass in der aktuellen Version von Python einige von moto usw. verwendete Funktionen gestoppt wurden. Diese Warnung wirkt sich nicht auf den Komponententest aus. Erstellen Sie daher eine Datei mit dem Namen "pytest.ini" in der Startseite des Projekts, schreiben Sie Folgendes und speichern Sie sie.

pytest.ini


[pytest]
filterwarnings =
    ignore::DeprecationWarning

Lass es uns erneut versuchen.

$ python -m pytest tests
============================= test session starts ==============================
platform darwin -- Python 3.8.5, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /Users/******/aws/github/sam-app, configfile: pytest.ini
plugins: mock-3.3.0
collected 1 item

tests/unit/test_handler.py .                                             [100%]

============================== 1 passed in 2.10s ===============================

Diesmal endete es ohne Vorwarnung.

Zusammenfassung

Es ist wünschenswert, dass der Komponententest automatisch ausgeführt wird, wenn der Quellcode geändert wird. Dieses Mal wird, da der Komponententest lokal ausgeführt wird, nur der Quellcodeteil geändert. Wenn es sich jedoch um eine Erweiterung der CI / CD-Pipeline handelt, sollte sie sich in "require.txt" oder in jeder Definitionsdatei befinden. Muss auch behoben werden. Das nächste Mal möchte ich irgendwann eine Überprüfung durchführen, einschließlich der Verbindung mit der Pipeline in diesem Bereich.

Beispielcode-Repository

https://github.com/hito-psv/test-demo-001

Recommended Posts

[AWS] Lassen Sie uns einen Komponententest der Lambda-Funktion in der lokalen Umgebung durchführen
Holen Sie sich den Aufrufer einer Funktion in Python
So testen Sie eine Funktion, die die aktuelle Zeit enthält, mit Freezegun in Python
Schreiben Sie die AWS Lambda-Funktion in Python
[Python] Machen Sie die Funktion zu einer Lambda-Funktion
Eine Funktion, die die Verarbeitungszeit einer Methode in Python misst
Erstellen Sie eine Funktion, um den Inhalt der Datenbank in Go abzurufen
Beweisen wir den Additionssatz einer Dreiecksfunktion, indem wir die Funktion durch eine Funktion in SymPy ersetzen (≠ Substitution).
Hinweise zur Verwendung von KUnit, dem Unit-Test-Mechanismus des Linux-Kernels
Schreiben Sie den Test in die Python-Dokumentzeichenfolge
Erstellen wir eine Chat-Funktion mit Vue.js + AWS Lambda + Dynamo DB [AWS-Einstellungen]
Führen Sie den Python-Interpreter im Skript aus
Bereiten Sie die Umgebung von Chainer auf der EC2-Spot-Instanz mit AWS Lambda vor
Lassen Sie uns das Bash-Skript in Java ausführen
Überprüfen Sie mit einem Test, wie oft die Abfrage (SQL) in Django ausgelöst wurde
[AWS Lambda] Erstellen Sie ein Bereitstellungspaket mit dem Amazon Linux Docker-Image
Anweisungen zum Verbinden von Google Colab mit der lokalen Laufzeit in einer Windows-Umgebung
Erstellen Sie in 1 Minute eine Vim + Python-Testumgebung
Führen Sie regelmäßig Python-Programme auf AWS Lambda aus
Zeichnen Sie in Python ein Diagramm einer quadratischen Funktion
Verwenden Sie den neuesten Pip in einer virtuellen Umgebung
Kopieren Sie die Liste in Python
Finden Sie die Anzahl der Tage in einem Monat
Legen Sie eine feste IP in der Linux-Umgebung fest
Korrigieren Sie die Argumente der in map verwendeten Funktion
Ausgabe in Form eines Python-Arrays
[Django] Lassen Sie uns versuchen, den Teil von Django zu klären, der im Test irgendwie durch war
Wenn eine lokale Variable mit demselben Namen wie die globale Variable in der Funktion definiert ist
Dies ist ein Beispiel für eine Funktionsanwendung im Datenrahmen.
Wird ab der Einführung von Node.js in der WSL-Umgebung verwendet
Die Geschichte des Aufbaus der schnellsten Linux-Umgebung der Welt
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
#Eine Funktion, die den Zeichencode einer Zeichenfolge zurückgibt
Ich habe versucht, TensorFlow in der AWS Lambda-Umgebung auszuführen: Vorbereitung
Verwenden wir die offenen Daten von "Mamebus" in Python
Lassen Sie uns die medizinische Kollapshypothese des neuen Koronavirus testen
Ein Memorandum über die Umsetzung von Empfehlungen in Python
Was bedeutet das letzte () in einer Funktion in Python?
Der Wert von meta beim Angeben einer Funktion ohne Rückgabewert mit Dask dataframe gilt
Die Geschichte des Debuggens in der lokalen Umgebung, weil die Kompilierung mit Read the Docs nicht funktioniert hat
Das Bild wird in der lokalen Entwicklungsumgebung angezeigt, aber das Bild wird nicht auf dem Remote-Server von VPS angezeigt.
Lassen Sie uns den Code des in Python [VS Code] geschriebenen automatischen E2E-Tests statisch überprüfen und formatieren.
Erstellen wir eine Funktion für den parametrisierten Test mithilfe eines Rahmenobjekts
Hinweis zum Standardverhalten von collate_fn in PyTorch
Finden Sie die scheinbare Breite einer Zeichenfolge in Python heraus
Ich habe den Super-Resolution-Algorithmus "PULSE" in einer Windows-Umgebung ausprobiert
Erstellen Sie einen lokalen Bereich in Python, ohne den Namespace zu verschmutzen
Überprüfen Sie die Funktionsweise von Python für .NET in jeder Umgebung
Wartung der Django + MongoDB-Entwicklungsumgebung (mitten im Schreiben)
Lassen Sie das Gleichungsdiagramm der linearen Funktion in Python zeichnen
Holen Sie sich die Anzahl der spezifischen Elemente in der Python-Liste
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
So entwickeln Sie in einer virtuellen Python-Umgebung [Memo]
[Hinweis] Import von Dateien in das übergeordnete Verzeichnis in Python
So führen Sie die Exportfunktion des GCP-Datenspeichers automatisch aus
Ändern des Aufbewahrungszeitraums für CloudWatch-Protokolle in Lambda