AWS CDKのテストを実行してみた(python編)
検証環境の情報
OS:macOS Monterey
IDE:Visual Studio Code
$ node --version
v14.17.6
$ cdk --version
2.40.0 (build 56ba2ab)
$ python --version
Python 3.8.13
CDKプロジェクトの作成
1.ディレクトリの作成
cdk-pythonというディレクトリを作成し、カレントを移動します
$ mkdir cdk-python && cd cdk-python
2.CDKの初期化
CDKはTypescript,Python,Java,C#,Gでプログラミングすることができます。
cdk init コマンドを実行する時に、--languageオプションで言語を指定します。
今回は、サンプルリソースを含めたCDKの初期化を行うため"sample-app"を指定しています。(後からテストコードを実行します)
サンプルリソースが不要時は"app"を指定して実行します
cdk init app --language [言語]
$ cdk init sample-app --language python
Applying project template sample-app for python
# Welcome to your CDK Python project!
:
Please run 'python3 -m venv .venv'!
Executing Creating virtualenv...
✅ All done!
// cdk init で生成されるディレクトリやファイル
$ tree
.
├── README.md
├── app.py
├── cdk.json
├── cdk_python
│ ├── __init__.py
│ └── cdk_python_stack.py
├── requirements-dev.txt
├── requirements.txt
├── source.bat
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_cdk_python_stack.py
2.python仮想環境に入ります
activateすると、プレフィックスに(.venv)が付与されます。
※抜ける場合は、deactivateを実行します
$ source .venv/bin/activate
(.venv) $
3.ライブラリのインストール
(.venv) $ pip install -r requirements.txt
app.pyの内容
#!/usr/bin/env python3
import aws_cdk as cdk
from cdk_python.cdk_python_stack import CdkPythonStack
app = cdk.App()
CdkPythonStack(app, "cdk-python")
app.synth()
cdk_python_stack.pyの内容
from constructs import Construct
from aws_cdk import (
Duration,
Stack,
aws_iam as iam,
aws_sqs as sqs,
aws_sns as sns,
aws_sns_subscriptions as subs,
)
class CdkPythonStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
queue = sqs.Queue(
self, "CdkPythonQueue",
visibility_timeout=Duration.seconds(300),
)
topic = sns.Topic(
self, "CdkPythonTopic"
)
topic.add_subscription(subs.SqsSubscription(queue))
4.スタック名の確認
(.venv) $ cdk list
cdk-python
5.CloudFormationTemplateの確認
(.venv) $ cdk synth
Resources:
CdkPythonQueueE793920B:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
Metadata:
aws:cdk:path: cdk-python/CdkPythonQueue/Resource
CdkPythonQueuePolicy645AC77E:
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Statement:
- Action: sqs:SendMessage
Condition:
ArnEquals:
aws:SourceArn:
Ref: CdkPythonTopic5B392E0B
Effect: Allow
Principal:
Service: sns.amazonaws.com
Resource:
Fn::GetAtt:
- CdkPythonQueueE793920B
- Arn
Version: "2012-10-17"
Queues:
- Ref: CdkPythonQueueE793920B
Metadata:
aws:cdk:path: cdk-python/CdkPythonQueue/Policy/Resource
CdkPythonQueuecdkpythonCdkPythonTopicA9819E1D183DEAD0:
Type: AWS::SNS::Subscription
Properties:
Protocol: sqs
TopicArn:
Ref: CdkPythonTopic5B392E0B
Endpoint:
Fn::GetAtt:
- CdkPythonQueueE793920B
- Arn
Metadata:
aws:cdk:path: cdk-python/CdkPythonQueue/cdkpythonCdkPythonTopicA9819E1D/Resource
CdkPythonTopic5B392E0B:
Type: AWS::SNS::Topic
Metadata:
aws:cdk:path: cdk-python/CdkPythonTopic/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/1WNQQ6CMBBFz8K+HVFcuOcCCO4NlBpHsIVOG0Oa3l3aJiZu5v//8pI5wbmEsug/xMU48RkH8J3txcR2dPe0Evirk06y+qFySbfRM4rtB/MMjNTud24gYXCxqFU0/vZNLygiTSWEWFtJ2hmRftRajRjNwJrNPrU6VHCBY1W8CJEbpyy+JbQ5v3NVS5++AAAA
Metadata:
aws:cdk:path: cdk-python/CDKMetadata/Default
Condition: CDKMetadataAvailable
Conditions:
CDKMetadataAvailable:
Fn::Or:
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- af-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-east-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-2
- Fn::Equals:
- Ref: AWS::Region
- ap-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-2
- Fn::Equals:
- Ref: AWS::Region
- ca-central-1
- Fn::Equals:
- Ref: AWS::Region
- cn-north-1
- Fn::Equals:
- Ref: AWS::Region
- cn-northwest-1
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- eu-central-1
- Fn::Equals:
- Ref: AWS::Region
- eu-north-1
- Fn::Equals:
- Ref: AWS::Region
- eu-south-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-2
- Fn::Equals:
- Ref: AWS::Region
- eu-west-3
- Fn::Equals:
- Ref: AWS::Region
- me-south-1
- Fn::Equals:
- Ref: AWS::Region
- sa-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-2
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- us-west-1
- Fn::Equals:
- Ref: AWS::Region
- us-west-2
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
テストの実行
1.テスト用ライブラリのインストール
pytestを使えるようにするため、requirements-dev.txtを指定してpip installを行います。
// requirement-dev.txtの中身には、pytestが記載されています
cat requirements-dev.txt
pytest==6.2.5
(.venv) $ pip install -r requirements-dev.txt
Collecting pytest==6.2.5
Using cached pytest-6.2.5-py3-none-any.whl (280 kB)
Collecting toml
Using cached toml-0.10.2-py2.py3-none-any.whl (16 kB)
Collecting py>=1.8.2
Using cached py-1.11.0-py2.py3-none-any.whl (98 kB)
Collecting iniconfig
Using cached iniconfig-1.1.1-py2.py3-none-any.whl (5.0 kB)
Collecting pluggy<2.0,>=0.12
Using cached pluggy-1.0.0-py2.py3-none-any.whl (13 kB)
Requirement already satisfied: attrs>=19.2.0 in ./.venv/lib/python3.8/site-packages (from pytest==6.2.5->-r requirements-dev.txt (line 1)) (22.1.0)
Collecting packaging
Using cached packaging-21.3-py3-none-any.whl (40 kB)
Collecting pyparsing!=3.0.5,>=2.0.2
Using cached pyparsing-3.0.9-py3-none-any.whl (98 kB)
Installing collected packages: iniconfig, toml, pyparsing, py, pluggy, packaging, pytest
Successfully installed iniconfig-1.1.1 packaging-21.3 pluggy-1.0.0 py-1.11.0 pyparsing-3.0.9 pytest-6.2.5 toml-0.10.2
2.テストコードの実行(pytest)
pytestコマンドを実行することでテストプログラムが実行されます。
まずは、cdk init sample-appで自動作成されたテストコードが正常に動作することを確認します。
// テストコードの実行
(.venv) $ pytest
================================================== test session starts ===================================================
platform darwin -- Python 3.8.13, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /Users/zigen/cdk_python
plugins: typeguard-2.13.3
collected 2 items
tests/unit/test_cdk_python_stack.py .. [100%]
=================================================== 2 passed in 6.96s ====================================================
上記のようなメッセージが表示されれば正常です。
それでは、テストコードで何を検証しているのか確認していきます。
3.スタックの内容
cdk_python_stack.py
・SQSキューの作成(可視性タイムアウトは300秒)
・SNSトピックの作成
・SNSトピックに送信されたメッセージをSQSに通知する
(SNSに対してSQSに通知するサブスクリプションを追加)
from constructs import Construct
from aws_cdk import (
Duration,
Stack,
aws_iam as iam,
aws_sqs as sqs,
aws_sns as sns,
aws_sns_subscriptions as subs,
)
class CdkPythonStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
queue = sqs.Queue(
self, "CdkPythonQueue",
visibility_timeout=Duration.seconds(300),
)
topic = sns.Topic(
self, "CdkPythonTopic"
)
topic.add_subscription(subs.SqsSubscription(queue))
4.テストコードの内容
test_cdk_python.stack.py
(1)test_sqs_queue_createdメソッド
CloudFormationTemplateのリソースプロパティに
"AWS::SQS::Queue", { "VisibilityTimeout": 300 }
が含まれていることを検証する
例)VisibilityTimeout(可視化タイムアウト)が100秒であればNG
(2)test_sns_topic_createdメソッド
CloudFormationTemplateに
"AWS::SNS::Topic"のリソースが 1つであることを検証する
例)複数のトピックが定義されている場合はNG
import aws_cdk as core
import aws_cdk.assertions as assertions
from cdk_python.cdk_python_stack import CdkPythonStack
def test_sqs_queue_created():
app = core.App()
stack = CdkPythonStack(app, "cdk-python")
template = assertions.Template.from_stack(stack)
template.has_resource_properties("AWS::SQS::Queue", {
"VisibilityTimeout": 300
})
def test_sns_topic_created():
app = core.App()
stack = CdkPythonStack(app, "cdk-python")
template = assertions.Template.from_stack(stack)
template.resource_count_is("AWS::SNS::Topic", 1)
5.期待値を変更し、テストNGにしてみる
期待値を変更し、テスコードがNGになることを試してみます。
VisibilityTimeout(可視化タイムアウト)の期待値を300秒から100秒に変更します。
// VisibilityTimeoutの期待値を300から100に変更する
template.has_resource_properties("AWS::SQS::Queue", {
"VisibilityTimeout": 100
})
pytestを実行すると、以下のようになります。
(.venv) $ pytest
:
E jsii.errors.JSIIError: Template has 1 resources with type AWS::SQS::Queue, but none match as expected.
E The closest result is:
E {
E "Type": "AWS::SQS::Queue",
E "Properties": {
E "VisibilityTimeout": 300
E },
E "UpdateReplacePolicy": "Delete",
E "DeletionPolicy": "Delete"
E }
E with the following mismatches:
E Expected 100 but received 300 at /Properties/VisibilityTimeout (using objectLike matcher)
.venv/lib/python3.8/site-packages/jsii/_kernel/providers/process.py:329: JSIIError
================================================================ short test summary info ================================================================
FAILED tests/unit/test_cdk_python_stack.py::test_sqs_queue_created - jsii.errors.JSIIError: Template has 1 resources with type AWS::SQS::Queue, but no...
============================================================== 1 failed, 1 passed in 7.35s ==============================================================
"Expected 100 but received 300 at …"
(テストコードの期待値は100だが、300が設定されている)
というメッセージを確認できます。
続いて、SNSトピック数の期待値を1から2に変更します。
// SNSトピック数の期待値を1から2に変更する
template.resource_count_is("AWS::SNS::Topic", 2)
再度、pytestを実行します。
(.venv) $ pytest
:
: 省略
:
E jsii.errors.JSIIError: Template has 1 resources with type AWS::SQS::Queue, but none match as expected.
E The closest result is:
E {
E "Type": "AWS::SQS::Queue",
E "Properties": {
E "VisibilityTimeout": 300
E },
E "UpdateReplacePolicy": "Delete",
E "DeletionPolicy": "Delete"
E }
E with the following mismatches:
E Expected 100 but received 300 at /Properties/VisibilityTimeout (using objectLike matcher)
.venv/lib/python3.8/site-packages/jsii/_kernel/providers/process.py:329: JSIIError
________________________________________________________________ test_sns_topic_created _________________________________________________________________
:
: 省略
:
E jsii.errors.JSIIError: Expected 2 resources of type AWS::SNS::Topic but found 1
.venv/lib/python3.8/site-packages/jsii/_kernel/providers/process.py:329: JSIIError
================================================================ short test summary info ================================================================
FAILED tests/unit/test_cdk_python_stack.py::test_sqs_queue_created - jsii.errors.JSIIError: Template has 1 resources with type AWS::SQS::Queue, but no...
FAILED tests/unit/test_cdk_python_stack.py::test_sns_topic_created - jsii.errors.JSIIError: Expected 2 resources of type AWS::SNS::Topic but found 1
=================================================================== 2 failed in 6.76s ===================================================================
"Expected 2 resources of type AWS::SNS::Topic but found 1"
(SNSトピックのリソース数は期待値は2つだが、1つ見つかった)
というメッセージを確認することができます。
参考サイト(AWS公式)
この記事が気に入ったらサポートをしてみませんか?