本記事ではPart2までで作成したスタックに対してAWS-CDKのassertions
を用いてテスト用のスクリプトを作成していきます。
環境情報
- 作業環境はAWS Cloud9を利用
- cdk versionは2.63.2
はじめに
今回はAWS公式ドキュメントで記されているFine-Grained Assertionsのテスト(Assertion Test)を実施していきます。
このテストスクリプトの中では主にhasResourceProperties
関数を用います。このヘルパー関数はCDKでリソースを作成する際に、"リソースが作成されていること”や"リソースに設定されているプロパティ値"の確認をする際に利用されます。
Assertion Tests
DynamoDB tableが作成されたことを確認するテスト
まずは不要なtest/cdk-workshop.test.ts
ファイルを削除してしまいましょう。その後test/hitcounter.test.ts
ファイルを作成し、以下のコードを記述します。
import { Template, Capture } from 'aws-cdk-lib/assertions';
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { HitCounter } from '../lib/hitcounter';
test('DynamoDB Table Created', () => {
const stack = new cdk.Stack();
// WHEN
new HitCounter(stack, 'MyTestConstruct', {
downstream: new lambda.Function(stack, 'TestFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'hello.handler',
code: lambda.Code.fromAsset('lambda')
})
});
// THEN
const template = Template.fromStack(stack);
template.resourceCountIs("AWS::DynamoDB::Table", 1);
});
このテストでは単純にスタックの中にDynamoDBのテーブルが含まれることをテストしています。
テストを実行します。
$ npm run test
以下のような結果が表示されます。
$ npm run test
> cdk-workshop@0.1.0 test
> jest
PASS test/hitcounter.test.ts (12.242 s)
✓ DynamoDB Table Created (177 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.439 s
Ran all test suites.
Lambda関数が作成されたことのテスト
次にLambda関数用のテストケースを追記していきます。今回はLambda関数が作成されたことに加えて、2つの環境変数(DOWNSTREAM_FUNCTION_NAME
とHITS_TABLE_NAME
)の値についてもテストしていきます。この2つの環境変数はPart2でLambda関数を作る際に指定しましたね。
この時点ではこの2つの環境変数にどの値がセットされるかわからない(この値はデプロイ時に決定されているものでしたね)ので、一旦ダミーの値をセットします。そのため初回のテストは失敗しますが、その失敗のログに実際の環境変数の値が出力されているので、その値を後ほど使います。
新規のテストケースを以下のように追記します。
test('Lambda Has Environment Variables', () => {
const stack = new cdk.Stack();
// WHEN
new HitCounter(stack, 'MyTestConstruct', {
downstream: new lambda.Function(stack, 'TestFunctioin', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'hello.handler',
code: lambda.Code.fromAsset('lambda')
})
});
// THEN
const template = Template.fromStack(stack);
const envCapture = new Capture();
template.hasResourceProperties("AWS::Lambda::Function", {
Environment: envCapture,
});
expect(envCapture.asObject()).toEqual(
{
Variables: {
DOWNSTREAM_FUNCTION_NAME: {
Ref: "TestFunctionXXXX",
},
HITS_TABLE_NAME: {
Ref: "MyTestConstructHitsXXXX",
}
},
}
);
});
ファイルを保存したのち、テストを実行します。
$ npm run test
以下のようにテスト結果にエラー1件が含まれています。エラーの中に指定すべき環境変数の値が記載されているので、こちらを使っていきます。
$ npm run test
> cdk-workshop@0.1.0 test
> jest
FAIL test/hitcounter.test.ts (13.577 s)
✓ DynamoDB Table Created (198 ms)
✕ Lambda Has Environment Variables (99 ms)
● Lambda Has Environment Variables
expect(received).toEqual(expected) // deep equality
- Expected - 2
+ Received + 2
Object {
"Variables": Object {
"DOWNSTREAM_FUNCTION_NAME": Object {
- "Ref": "TestFunctionXXXX",
+ "Ref": "TestFunctioin03257049",
},
"HITS_TABLE_NAME": Object {
- "Ref": "MyTestConstructHitsXXXX",
+ "Ref": "MyTestConstructHits24A357F0",
},
},
}
41 | });
42 |
> 43 | expect(envCapture.asObject()).toEqual(
| ^
44 | {
45 | Variables: {
46 | DOWNSTREAM_FUNCTION_NAME: {
at Object.<anonymous> (test/hitcounter.test.ts:43:33)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 13.766 s
Ran all test suites.
では上記エラーで表示された値を使ってテストケースの内容を書き換えます。
...
expect(envCapture.asObject()).toEqual(
{
Variables: {
DOWNSTREAM_FUNCTION_NAME: {
Ref: "ここにログで確認した値をセット",
},
HITS_TABLE_NAME: {
Ref: "ここにログで確認した値をセット",
}
},
}
);
...
再びテストを実行すると、今度は成功しました!
$ npm run test
> cdk-workshop@0.1.0 test
> jest
PASS test/hitcounter.test.ts (12.738 s)
✓ DynamoDB Table Created (150 ms)
✓ Lambda Has Environment Variables (94 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 12.942 s, estimated 14 s
Ran all test suites.
TDD (Test Driven Development)
CDKでスタックを作成する際にTDDの手法を用いることも可能です。簡単な例として、既存のDynamoDBテーブルを暗号化するという新規の要件があったとします。
TDDアプローチとしては、まずこの要件をテストスクリプトに反映させます。
test('DynamoDB Table Created With Encryption', () => {
const stack = new cdk.Stack();
// WHEN
new HitCounter(stack, 'MyTestConstruct', {
downstream: new lambda.Function(stack, 'TestFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'hello.handler',
code: lambda.Code.fromAsset('lambda')
})
});
// THEN
const template = Template.fromStack(stack);
template.hasResourceProperties("AWS::DynamoDB::Table", {
SSESpecification: {
SSEEnabled: true
}
});
});
テストを実行してみるとエラーとなると思います。暗号化する設定をコンストラクタに記載していないので、想定通りですね。
ではコンストラクタをアップデートして、DynamoDBテーブルに対して暗号化されるように記載していきましょう。
...
constructor(scope: Construct, id: string, props: HitCounterProps) {
super(scope, id);
const table = new dynamodb.Table(this, 'Hits', {
partitionKey: { name: 'path', type: dynamodb.AttributeType.STRING },
encryption: dynamodb.TableEncryption.AWS_MANAGED
});
...
再度テストを実施してみると、今回は成功するかと思います。
このようにCDKを用いることでTDDのアプローチも可能ですね!
まとめ
いかがでしたでしょうか。クラウドインフラに対して、構築物をテストする際にコンソールでの目視確認を実施しているようなプロジェクトも多いかと思います。CDKを用いれば、AWSサービス構築時に想定通りの内容が反映されているかテストもできるので、DevOpsのサイクルもより迅速に回せそうな気がしますね!
参考サイト