はじめに
最近はAWS CDKでリソースを構築することが多いのですが、AWS CDKは一般的なプログラミング言語でAWSのリソースを定義するものなので、テストコードを書くことができます。そのテストコードの書き方についてまとめてみます。
前提条件
本記事は、以下の言語とAWS CDKのバージョンについて記しています。
- TypeScript
- AWS CDK 2.118.0
公式ドキュメント
AWS CDKの公式ドキュメントにテストについて記されたページがあるので目を通します。が、機械翻訳での提供なので、英語版を読んだ方が良いかもしれません。
テストのカテゴリ
上記公式ドキュメントに記されていますが、テストには以下2つのカテゴリがあるようです。
- きめ細やかなアサーション(Fine-grained assertions)
- AWS CDKが生成するCloudFormationの各種設定値が期待通りに生成されているかテストする
- スナップショット(Snapshot test)
- AWS CDKが生成するCloudFormationのテンプレートを以前のものと比較し、差分があるかをテストする
開発中は「きめ細やかなアサーション(Fine-grained assertions)」でテストを書いて、本番運用後は「スナップショット(Snapshot test)」を組み合わせる感じかなと考えました。
今回は「きめ細やかなアサーション(Fine-grained assertions)」の書き方について記します。
実装
cdk init
にてプロジェクトを生成すると以下のようなサンプルテストコード込みで生成されるので、それを拡張するようにします。
// import * as cdk from 'aws-cdk-lib'; // import { Template } from 'aws-cdk-lib/assertions'; // import * as Cdk from '../lib/cdk-stack'; // example test. To run these tests, uncomment this file along with the // example resource in lib/cdk-stack.ts test('SQS Queue Created', () => { // const app = new cdk.App(); // // WHEN // const stack = new Cdk.CdkStack(app, 'MyTestStack'); // // THEN // const template = Template.fromStack(stack); // template.hasResourceProperties('AWS::SQS::Queue', { // VisibilityTimeout: 300 // }); });
template
変数を生成するまではいわゆるおまじないなので、ある程度コピペで。stack
変数を生成するnew Cdk.CdkStack(app, 'MyTestStack');
は適宜自分が生成したいStackに合わせて修正するぐらいです。
AWS CDKはCloudFormationを生成するので、CloudFormationの値が想定値と一致しているかどうかをテストするのが基本的な戦略になるかなと思います。AWS CDKのaws-cdk-lib.assertions
モジュールにて、各種Matcherの説明があるのでこれがテストコードの実装の拠り所になるかなと思います。
個人的には、以下のMatcherを使うことが多いです。
resourceCountIs
- 対象のリソースが想定する数作成されるか
hasResourceProperties
- 対象のリソースのプロパティが想定している値であるか
hasResource
- 対象のリソースのプロパティ以外の設定(
DeletionPolicy
など)の値が想定しているものか
- 対象のリソースのプロパティ以外の設定(
繰り返しになりますが、AWS CDKはCloudFormationを生成するので、各種検証する値はCloudFormationのドキュメントも合わせて確認することになるかなと思います。
利用するサービスに対してCloudFormationの知識がないとテストも書きにくいと思います。この辺がちょっとハードルが高いかなと思いますが、一回ですべてを網羅するのは難しいので徐々に書き足す形が良いのかなと思っています。
なお、AWSの各種サービスは日々バージョンアップが行われ、AWS CDK自身も頻繁にバージョンアップされています。以下のページを見ると、1ヶ月に4回以上はザラにアップデートされています。
CloudFormationのドキュメントにはあるのにAWS CDKにはない場合にはAWS CDKのバージョンアップを実施するとサクッと解決することが多いかなと思います。
実行
実行はnpm run test
で実行できます。実行後、失敗するとどこで失敗したかがわかるように表示されます。ここらへんはJtestの機能です。
% npm run test > cdk@0.1.0 test > jest FAIL test/cdk.test.ts ✕ ECRが1つ作成されること (82 ms) ● ECRが1つ作成されること Template has 1 resources with type AWS::ECR::Repository, but none match as expected. The 1 closest matches: Repository22E53BBD :: { "DeletionPolicy": "Delete", "Properties": { !! Expected false but received true "EmptyOnDelete": true, "RepositoryName": "my-ruby-app" }, "Type": "AWS::ECR::Repository", "UpdateReplacePolicy": "Delete" } 9 | 10 | template.resourceCountIs('AWS::ECR::Repository', 1); > 11 | template.hasResourceProperties('AWS::ECR::Repository', { | ^ 12 | RepositoryName: 'my-ruby-app', 13 | EmptyOnDelete: false, 14 | }); at Template.hasResourceProperties (node_modules/aws-cdk-lib/assertions/lib/template.js:1:3101) at Object.<anonymous> (test/cdk.test.ts:11:12) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 1.696 s, estimated 2 s
成功すると、以下のように表示されます。
% npm run test > cdk@0.1.0 test > jest PASS test/cdk.test.ts ✓ ECRが1つ作成されること (83 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.712 s Ran all test suites.
考察
AWS CDK自身は1ヶ月に複数回バージョンアップされています。クラウドの更新頻度を踏まえるとそれぐらいのバージョンアップは必然かなと思います。そのバージョンアップに追随するためにはテストコードを書くのは自然な発想と考えています。世の中、AWS CDKを使ってリソースを作ることは書かれていますが、テストコードの書き方は書かれていなかったので今回記事化しました。
実際には、AWS CDK、CloudFormation、Jestの知識がいるのでテストを書くとなるとハードルが高いなと感じます。ですが、一度に書き上げるのではなく徐々に作り上げていくとよいのかなと思いました。
ここで書いたのはあくまで基本的な記述方法で、上記のマニュアルにもいろんな検証方法が掲載されています。それらも実際の利用シーンとあわせて実装してみることが今後の課題です。
また、カバレッジを取得することはできないのかなと思ったりもしました。AWS CDKではそんなに複雑なことをしないケースがほとんどですのであまりニーズはないのかもしれません。