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.
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
Installieren Sie die Python-Pakete, die zum Ausführen des Komponententests erforderlich sind.
$ pipenv install pytest pytest-mock mocker moto --dev
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.
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
}),
}
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
test_lambda_handler
eine Pseudo-DynamoDB-Tabelle, bevor Sie die Lambda-Funktion aufrufen.ist.
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.
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.
https://github.com/hito-psv/test-demo-001