Terraform のテスト機能を試してみた
こんにちは、クラウドエースの佐久間です。2023 年 10 月 5 日にリリースされた GA 版 Terraform v1.6.0 において、terraform test
コマンドを用いたテスト機能が正式に実装されました。この記事では、公式ページの説明をまとめるとともに、Google Cloud のリソースを用いてそのテスト機能を簡単に試していきます。なお、Terraform の基本的な使い方には触れませんのでご了承ください。
機能概要
この機能は、テストファイルに書かれたテストコードに基づき、モジュール構成の更新にミスがないかテストするための機能です。terraform test
コマンドを実行することでテストが走ります。
これまで Terraform コードのテストには、Terratest や Kitchen-Terraform といった外部ツールを利用する必要がありました。これらのツールは HCL 以外の言語でテストコードを作成する必要があるため、テストを行うにも学習コストがかかります。
今回のテスト機能が実装されたことで、テストコードを HCL で作成できるようになり、テストを Terraform 内で完結できるようになりました。テストを実行すると、テスト用のリソースが一時的に作成され、それらのリソースに対してテストが実行されます。これにより、コード編集による重大な変更の防止や、設定値の誤りの検証ができます。
使い方
基本的な使い方は、テストコードが書かれたテストファイルを作成し、terraform test
コマンドを実行するだけです。デフォルト設定時の terraform test
コマンドの大まかな動作は以下のようになります。
- テストファイルを検出する
- テストファイルに記載されているテスト用リソースを作成する
- 作成されたリソースに対して、テストファイルで指定した結果になっているかチェックする (アサーション)
- テスト用リソースを削除する
テストファイル
Terraform は .tftest.hcl
または .tftest.json
のファイル拡張子に基づいてテストファイルを検出します。テストファイルは以下のブロックを含みます。
- 1 つ以上の
run
ブロック (詳細は次のセクションで説明します) -
variables
ブロック (省略可)|構成内の入力変数の値を指定 -
provider
ブロック (省略可)|構成内に必要なプロバイダーを設定または上書き
run
ブロック
各 run
ブロックは以下のフィールドまたはブロックを含みます。
フィールドまたはブロック名 | 説明 | デフォルト値 |
---|---|---|
command |
apply または plan を指定。plan を指定するとリソースの作成を行わず、plan の結果のみでテストを行う。 |
apply |
plan_options.mode |
command = plan で実行したときのモード選択。normal または refresh-only を指定。詳細はこちら。 |
normal |
plan_options.refresh |
command = plan で実行したときのコマンド オプション。true または false を指定。詳細はこちら。 |
true |
plan_options.replace |
command = plan で実行したときのコマンド オプション。詳細はこちら。 |
|
plan_options.target |
command = plan で実行したときのコマンド オプション。詳細はこちら。 |
|
variables |
変数を記載。メインの構成やrun ブロックの外で定義した変数を上書きできる。詳細はこちら。 |
|
module |
run ブロックを実行するモジュールの変更。詳細はこちら。 |
|
providers |
メインの構成に必要なプロバイダーを設定または上書きする。詳細はこちら。 | |
assert |
condition (テストをパスするための条件) や error_message (テスト失敗時のエラー メッセージ) を記載。 |
|
expect_failures |
あらかじめブロック内のテストが失敗すると分かっている場合に、そのテストをパスさせる。詳細はこちら。 |
使用例
今回は以下のような main.tf
を作成し、 プロジェクトに Google Cloud Storage バケットを作成することを前提とします。
variable "project" {
type = string
}
resource "google_storage_bucket" "main" {
name = "ca-terraform-test-bucket"
location = "asia-northeast1"
force_destroy = true
project = var.project
}
また、作成したテストファイルは以下の通りです。今回は main.tftest.hcl
というファイル名で作成しました。
run "check_bucket_name" {
command = plan
assert {
condition = google_storage_bucket.main.name == "ca-terraform-test-bucket"
error_message = "Bucket name is not ca-terraform-test-bucket"
}
}
run "check_bucket_location" {
command = plan
assert {
condition = google_storage_bucket.main.location == "ASIA-NORTHEAST1"
error_message = "Bucket location is not ASIA-NORTHEAST1"
}
}
2 つの run
ブロックを用意しました。1 つ目のブロックではバケット名をチェックし、2 つ目のブロックではバケットのロケーションをチェックしています。
それでは早速テストを実行してみます。
$ terraform test
main.tftest.hcl... in progress
run "check_bucket_name"... pass
run "check_bucket_location"... pass
main.tftest.hcl... tearing down
main.tftest.hcl... pass
Success! 2 passed, 0 failed.
いずれのブロックもテストをパスしました。次に、main.tf
を以下のように変更してみます。
resource "google_storage_bucket" "main" {
name = "ca-terraform-test-bucket"
location = "us-central1"
force_destroy = true
}
ロケーションを asia-northeast1
から us-central1
に変更しました。この状態で再度テストを実行してみます。
$ terraform test
main.tftest.hcl... in progress
run "check_bucket_name"... pass
run "check_bucket_location"... fail
╷
│ Error: Test assertion failed
│
│ on main.tftest.hcl line 10, in run "check_bucket_location":
│ 10: condition = google_storage_bucket.main["ca-terraform-test-bucket"].location == "ASIA-NORTHEAST1"
│ ├────────────────
│ │ google_storage_bucket.main["ca-terraform-test-bucket"].location is "US-CENTRAL1"
│
│ Bucket location is not ASIA-NORTHEAST1
╵
main.tftest.hcl... tearing down
main.tftest.hcl... fail
Failure! 1 passed, 1 failed.
main.tf
とテストファイルで指定したロケーションが異なるため、期待通りエラー メッセージとともにテストは失敗しました。1 つ目のブロックのテストはパスしていますが、2 つ目で失敗しているので、全体としてもテストは失敗したことになります。
まとめ
新しく実装された Terraform のテスト機能について簡単に説明しました。これまで他のツールを用いて行われてきた Terraform コードのテストが Terraform だけで完結するので、かなり便利だと感じました。例として実践したテストはかなり簡単なものですが、より複雑なテストのやり方も今後調べていきたいと思います。
Discussion