実践!AWS CDK #3 テスト
はじめに
今回は AWS CDK ならではの機能、テスト について学んでいきましょう。前回作成した VPC に関するテストコードも書いていきます。
前回の記事はこちら。
AWS CDK におけるテスト
AWS CDK ではテストは以下 3 つのカテゴリに分類されます。
Snapshot tests
テスト実行時点で作成される CFn テンプレート(スナップショット)と事前に保存されている ベースラインテンプレート を比較してテストします。以下のコードでこの比較処理を実施します。(初回は比較なしで passed)
expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot();
比較した結果、マッチしていれば passed, していなければ failed となります。failed となってもそれが意図した変更であれば次のコマンドでベースラインテンプレートを更新できます。
$ npm test -- -u
「あなたの変更でここが変わってるけど、意図してる?」ということが確認できるテストです。L2 の Construct を使用する際は便利かもしれませんね。(意図しないリソース作成防止)
当然ながら設定値を変更した場合や新たなリソースを追加した場合は必ず failed となってしまいます(passed にするためには failed > 更新 > passed という手順が必要)。私はこの挙動が少し気になり、かつ L2 の Construct は扱わないため本シリーズにおいてこのテストは採用しません。
Fine-grained assertions
生成された CFn テンプレートの一部をテストできます。新たに追加したリソースのプロパティのチェックやリファクタリング等で既存のリソースに影響がないことを確認できます。
以下のような項目をチェックできます。
- どんなリソースがあるか
- リソースのプロパティ
- リソースの数
- 出力(Outputs)の内容
本シリーズではこのテストを採用します。
Validation tests
Construct が無効なデータを受け取った時にエラー(例外)を発生させることを確認するテストです。以下のサンプルは retentionDays
に無効な値を入れた場合に意図した例外が発生することを確認しています。
test('configurable retention period cannot exceed 14 days', () => { const stack = new Stack(); expect(() => { new dlq.DeadLetterQueue(stack, 'DLQ', { retentionDays: 15 }); }).toThrowError(/retentionDays may not exceed 14 days/); });
一般的な 単体テスト に近い印象を受けました。
複雑な Construct を使用する予定はないので本シリーズにおいてこのテストは採用しません。
なお私の環境だと、この toThrowError()
メソッドが利用できません(?)
インストール
テスト用のフレームワークをインストールするには以下のコマンドを実行します。
$ npm install --save-dev jest @types/jest @aws-cdk/assert
続いてルートディレクトリ直下にある package.json
を以下のように編集します。
{ ... "scripts": { ... "test": "jest" }, "devDependencies": { ... "@types/jest": "^24.0.18", "jest": "^24.9.0", }, "jest": { "moduleFileExtensions": ["js"] } }
私の環境では scripts
と devDependencies
は既に項目が存在したので、jest
部分だけ追記しました。
これで準備完了です。
一度以下のコマンドでテストを実行してみましょう。
$ npm run build && npm test
実行できて failed
になれば OK です。
~ 省略 ~ Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 4.148 s Ran all test suites.
実装
それではテストコードを書いていきましょう。
今回編集するファイルは test
ディレクトリにある devio.test.ts
となります。現在の状態がこちら。
import { expect as expectCDK, matchTemplate, MatchStyle } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; import * as Devio from '../lib/devio-stack'; test('Empty Stack', () => { const app = new cdk.App(); // WHEN const stack = new Devio.DevioStack(app, 'MyTestStack'); // THEN expectCDK(stack).to(matchTemplate({ "Resources": {} }, MatchStyle.EXACT)) });
このテストはプロジェクト作成時に自動生成されるもので、リソースが空({}
)であることを確認するテストです。しかし前回 VPC リソースを作成しており、リソースが空ではなくなったため先程のテストに失敗したというわけです。
今回書く(書いた)テストコードはこちら。
import { expect, countResources, haveResource } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; import * as Devio from '../lib/devio-stack'; test('Vpc', () => { const app = new cdk.App(); const stack = new Devio.DevioStack(app, 'DevioStack'); expect(stack).to(countResources('AWS::EC2::VPC', 1)); expect(stack).to(haveResource('AWS::EC2::VPC', { CidrBlock: '10.0.0.0/16', Tags: [{ 'Key': 'Name', 'Value': 'devio-stg-vpc' }] })); });
まず以下のコードで VPC のリソースが 1 つであることを確認しています。1
の部分を他の値に変更するとテストは失敗します。
expect(stack).to(countResources('AWS::EC2::VPC', 1));
次に作成した VPC リソースのプロパティをチェックしています。
expect(stack).to(haveResource('AWS::EC2::VPC', { CidrBlock: '10.0.0.0/16', Tags: [{ 'Key': 'Name', 'Value': 'devio-stg-vpc' }] }));
haveResource
メソッドや countResources
メソッドの第一引数にはリソースタイプを string 型で指定します。ここに指定すべき文字列は CFn でサポートされている リソースタイプ識別子 となります。
これらが string 型となっていることから予想できますが、プロパティ部分に関しては IDE の補完が効きません。またここで指定すべきプロパティのキー値は CFn のドキュメントに書かれているもの となります。具体的に言うと CfnVPCProps の cidrBlock
は無効であり、AWS::EC2::VPC の CidrBlock
(先頭大文字!)が有効な値となるのでご注意ください。テスト時は生成された CFn のテンプレートと比較を行っているので、CFn の仕様が正となります。
今回実装してはいませんが、あるプロパティが 指定されていないこと を確認することもできます。(ABSENT
)
expect(stack).to(haveResource('AWS::EC2::VPC', { CidrBlock: ABSENT }));
CidrBlock
が指定されていなければ passed。今回は指定しているので failed となります。
本シリーズでは今後これくらいのレベルでテストコードを書いていこうと思います。
確認
それでは改めてテストを実行してみましょう。
$ npm run build && npm test ~ 省略 ~ Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.69 s, estimated 3 s Ran all test suites.
無事にテストが通りました。この結果により VPC が意図通りの数とプロパティで生成されることが保証されます。これで安心してリファクタリングができますね!
GitHub
今回のソースコードは コチラ です。
おわりに
以上が AWS CDK におけるテストの概要となります。
テストに正解はありませんが、自身が安心して実装できるよう常にメンテナンスしていきたいですね。興味がある方は以下のリンクから、自分に合うテスト方法を見つけてみてください。