Cette fois, je voudrais vérifier sur les hypothèses suivantes.
Si vous utilisez SAM, vous pouvez construire DynamoDB etc. dans un pseudo environnement local en utilisant l'environnement Docker, mais cette fois, je voudrais vérifier le test avec un œil sur le test unitaire (futur test automatique). Je pense.
Alors, tout d'abord, créez un projet. Si vous n'êtes pas sûr de créer un projet avec SAM, veuillez le faire à l'avance.
Nous vous recommandons de lire attentivement.
$ 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
Installez les packages Python nécessaires pour exécuter le test unitaire.
$ pipenv install pytest pytest-mock mocker moto --dev
Vous pouvez appeler les fonctions Lamnda avec les commandes suivantes pour exécuter un test unitaire pour chaque fonction Lambda. Tout d'abord, exécutons un test de la fonction Lambda de HelloWorld qui est créée par défaut (ce code de test est également créé par défaut).
$ 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 ===============================
Vous pouvez voir qu'un test a réussi.
Cette fois, étant donné que le but est uniquement pour les tests unitaires, nous n'effectuerons que les modifications nécessaires pour le test sans modifier les paramètres SAM. Maintenant, ajoutons un processus pour accéder (ajouter un enregistrement) DynamoDB.
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()
Les principales corrections sont
--Ajout de définitions requises pour l'importation
--Ajout de @ mock_dynamodb2
avant test_lambda_handler
--Avec test_lambda_handler
, créez une pseudo table DynamoDB avant d'appeler la fonction Lambda.
est.
Maintenant, exécutons le test unitaire immédiatement.
$ 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
Cela a réussi, mais je reçois un avertissement.
Cela signifie que dans la version actuelle de Python, certaines fonctions utilisées par moto etc. ont été arrêtées.
Cet avertissement n'affecte pas le test unitaire, alors créez un fichier avec le nom pytest.ini
dans la maison du projet, écrivez ce qui suit et enregistrez-le.
pytest.ini
[pytest]
filterwarnings =
ignore::DeprecationWarning
Essayons encore.
$ 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 ===============================
Cette fois, cela s'est terminé sans avertissement.
Il est souhaitable que le test unitaire soit exécuté automatiquement lorsque le code source est modifié.
Cette fois, comme le test unitaire est exécuté localement, seule la partie du code source est modifiée, mais s'il s'agit d'une extension du pipeline CI / CD, elle doit être dans requirements.txt
ou dans chaque fichier de définition. Doit également être corrigé.
La prochaine fois, j'aimerais faire une vérification à un moment donné, y compris la connexion avec le pipeline dans ce domaine.
https://github.com/hito-psv/test-demo-001
Recommended Posts