ようこそ!インフラエンジニアの最高峰を目指す皆さん。
クラウドインフラをコードで管理する「Infrastructure as Code(IaC)」の代表格、Terraform。これまでTerraformのテストといえば、`terraform plan` で変更差分を目視確認するか、Go言語を使って `terratest` などの外部ツールで実際にクラウド上にリソースを仮作成(インテグレーションテスト)するのが主流でした。
しかし、こう思ったことはありませんか?
「ただの命名規則のチェックや、タグの付与漏れを検証したいだけなのに、なぜわざわざクラウド上に実際の物理リソースを何分もかけて作り、無駄な課金リスクを侵さなきゃいけないんだ…?」
その悩みを根本から解決するために登場したのが、Terraform 1.6で正式実装され、1.7で超強力な「モック(Mock)機能」が追加されたネイティブの `test` コマンドです!
これをマスターすれば、「AWSやGCPに1回もリクエストを送ることなく、わずか数秒でインフラコードのロジックが正しいかを自動検証する」という、極上の開発体験が手に入ります。夜も安心して熟睡できるようになりますよ。
今回は、初心者のあなたに向けて、この画期的なテストフレームワークの仕組みから、モックを使った安全な「Hello World」単体テストの実行まで、手取り足取り優しく解説します。一緒に一歩を踏み出しましょう!
—
1. `terraform test` とモック(Mock)の役割とは?
まずは全体のイメージを掴みましょう。
これまでのテスト手法と、Terraform 1.6以降の新機能を比べると以下のようになります。
| テスト手法 | 検証スピード | クラウド課金・リスク | 外部ツールの学習 | 役割 |
| :— | :— | :— | :— | :— |
| `terraform plan` | 爆速 | なし | 不要 | 設定の文法エラーと差分チェック(ロジック検証は不可) |
| 従来の統合テスト | 激重(数分〜数十分)| あり(実際に作るため) | 必要(Go言語など) | 本番さながらのリソース連携テスト |
| `terraform test` + モック | 爆速(数秒) | 完全ゼロ(安全) | 不要(HCLのみ) | 条件分岐や変数バリデーションの単体テスト |
モック(Mock)ってなに?
モックとは、一言で言えば「AWSやGCPのダミー(偽物)」です。
通常、Terraformは `aws_s3_bucket` などを記述すると、AWS APIを叩いて通信を行います。しかし、テスト時にモックを使うと、Terraform内部で「AWS APIを呼び出したフリ」をして、定義されたダミーの戻り値を返してくれます。
これにより、認証情報(APIキーなど)すら不要で、オフライン環境でも瞬時にインフラの単体テスト(Unit Test)が完了するのです。
—
2. 事前準備:開発環境の確認
本記事の「モック機能を使った極上の単体テスト」を体験するには、Terraform 1.7.0 以上が推奨となります(1.6でも基本テストは動きますが、モックは1.7で大幅強化されました)。
まずは端末のターミナル(またはコマンドプロンプト)を開き、バージョンを確認してみましょう。
terraform version
もし `Terraform v1.7.x` 以上の表示が出れば準備完了です!
(まだインストールしていない、あるいは古い場合は、tfenvなどのバージョン管理ツールや公式サイトから最新版を取得してくださいね)
—
3. 実践!はじめてのインフラ単体テスト(ハンズオン)
それでは、実際に手を動かしていきましょう!
今回は「社内のルールに従って、正しい命名規則と環境タグが付与されたS3バケットを作成するコード」を題材にします。
プロジェクトのディレクトリ構成
作業用フォルダを作成し、以下のような構成を作ります。
my-terraform-project/
├── main.tf # メインのリソース定義
├── variables.tf # 入力変数の定義
├── outputs.tf # 出力値の定義
└── tests/ # ★テストコードを入れる専用ディレクトリ
└── s3_bucket_test.tftest.hcl # ★テストファイル(拡張子: .tftest.hcl)
—
ステップ1:本体コードの記述
まずは、テスト対象となるTerraformコードを作成します。
`variables.tf`(入力変数)
環境名を受け取る変数(dev, stg, prd のみを許可したい)
variable “environment” {
type = string
description = “デプロイ先の環境名 (dev / stg / prd)”
validation {
condition = contains([“dev”, “stg”, “prd”], var.environment)
error_message = “environment は ‘dev’, ‘stg’, ‘prd’ のいずれかで指定してください。”
}
}
サービス名を受け取る変数
variable “service_name” {
type = string
description = “サービス名(小文字の英数字とハイフンのみ)”
default = “my-app”
}
`main.tf`(リソース定義)
terraform {
required_version = “>= 1.7.0”
required_providers {
aws = {
source = “hashicorp/aws”
version = “~> 5.0”
}
}
}
AWSプロバイダーの設定(モックを使うため、実際のAWS認証情報は不要です!)
provider “aws” {
region = “ap-northeast-1”
}
S3バケットの定義
命名規則: [サービス名]-[環境名]-bucket
resource “aws_s3_bucket” “app_bucket” {
bucket = “${var.service_name}-${var.environment}-bucket”
tags = {
Environment = var.environment
ManagedBy = “Terraform”
}
}
`outputs.tf`(出力定義)
テストで検証しやすくするために、作成されたバケット名をoutputに出力
output “bucket_name” {
value = aws_s3_bucket.app_bucket.bucket
description = “作成されたS3バケットの名前”
}
—
ステップ2:テストコードの記述(ここが本番!)
次に、作成したコードが「意図通りに動くか」を検証するテストコードを書きます。
ファイルは必ず `tests/` ディレクトリ配下に配置し、拡張子を `.tftest.hcl` にします。
`tests/s3_bucket_test.tftest.hcl`
——————————————————————————
1. モックプロバイダーの設定(AWSと通信させないための魔法のおまじない)
——————————————————————————
mock_provider “aws” {}
——————————————————————————
2. テストケース1:正常系(正しい変数を渡したときに、名前とタグが正しく生成されるか)
——————————————————————————
run “verify_s3_bucket_creation_success” {
# テストコマンド実行時に流し込む変数を定義
variables {
environment = “dev”
service_name = “awesome-service”
}
# 【検証1】S3バケットの命名規則が “[service_name]-[environment]-bucket” になっているか?
assert {
condition = aws_s3_bucket.app_bucket.bucket == “awesome-service-dev-bucket”
error_message = “S3バケット名が命名規則に合致していません。”
}
# 【検証2】Environmentタグに正しい値が入っているか?
assert {
condition = aws_s3_bucket.app_bucket.tags[“Environment”] == “dev”
error_message = “Environmentタグの値が不正です。”
}
}
——————————————————————————
3. テストケース2:異常系(不正な環境名を渡したときに、正しくエラーになるか)
——————————————————————————
run “verify_invalid_environment_fails” {
command = plan # バリデーションチェックのみを行うため plan を指定
variables {
environment = “invalid_env” # 許可されていない環境名
service_name = “awesome-service”
}
# 不正な入力に対してバリデーションエラーが起きることを期待するテスト
expect_failures = [
var.environment,
]
}
—
4. テストを実行してみよう!
さあ、魔法のコマンドを叩く瞬間がやってきました。
プロジェクトのルートディレクトリで、以下のコマンドを実行します。
terraform test
すると……わずか数秒で、ターミナルに美しいテスト結果が表示されます!
tests/s3_bucket_test.tftest.hcl… building test execution plan
tests/s3_bucket_test.tftest.hcl… running
run “verify_s3_bucket_creation_success”… pass
run “verify_invalid_environment_fails”… pass
Success! 2 passed, 0 failed.
たったこれだけです!AWSのクレデンシャル(`AWS_ACCESS_KEY_ID` など)を設定していなくても、エラーにならずに一瞬でテストが成功したはずです。これがモックを使った単体テストの破壊的な威力です。
—
失敗ケースも体験しておこう(あえて落とすテスト)
テストの真価を知るために、あえてコードをバグらせてみましょう。
`main.tf` のバケット名の定義を以下のように書き換えてみます(`-bucket` を付け忘れたバグを模倣)。
あえてバグを仕込む(-bucket を消してみる)
resource “aws_s3_bucket” “app_bucket” {
bucket = “${var.service_name}-${var.environment}”
…
この状態で再度 `terraform test` を実行してみてください。
tests/s3_bucket_test.tftest.hcl… building test execution plan
tests/s3_bucket_test.tftest.hcl… running
run “verify_s3_bucket_creation_success”… fail
run “verify_invalid_environment_fails”… pass
── Failure ───────────────────────────────────────────────────────────────────
Failure: S3バケット名が命名規則に合致していません。
on tests/s3_bucket_test.tftest.hcl line 19, in run “verify_s3_bucket_creation_success”:
19: condition = aws_s3_bucket.app_bucket.bucket == “awesome-service-dev-bucket”
Failure! 1 passed, 1 failed.
見事に `S3バケット名が命名規則に合致していません。` という自分で書いた親切なエラーメッセージとともにテストが落とされましたね!
本番環境に適用(apply)する前に、手元のローカル環境で瞬時にバグを発見できました。
確認が終わったら、`main.tf` を元の正しい記述に戻しておきましょう。
—
5. 現場で差がつく!先輩エンジニア直伝の活用ノウハウ
この `terraform test` を日々の業務でさらに活用するための、プロの極意を3つ伝授します。
① GitHub ActionsなどのCI/CDに組み込む
Pull Request(PR)が作成された際、自動で `terraform test` が走るようにGitHub Actionsを設定しましょう。
モックを使っていればクラウドの認証情報(AWS IAMロールなど)をCIに渡す必要すらありません。セキュアかつ高速に、メンバーが書いたコードの品質を自動で担保できます。
② 「単体テスト(Mock)」と「統合テスト」を使い分ける
- 単体テスト(今回学んだ方法): モックを使い、命名規則、タグ付けルール、`count` や `for_each` によるリソース生成ロジックの正しさを高速検証する。
- 統合テスト: `mock_provider` を使わずに実際の開発用AWS環境へ接続し、APIの仕様変更やリソース同士の依存関係が崩れていないかをじっくり検証する。
この2層構造を作るのが、現代の最強のインフラテスト戦略です。
③ 複雑なモジュール作成時こそ真価を発揮する
社内共通の「Terraformモジュール(共通パーツ)」を作る際、様々なパラメータ(変数)に対応させるためにコードが複雑化しがちです。
パラメータの組み合わせごとに `run` ブロックを複数書くことで、「このパラメータを渡したら正しくセキュリティグループが構成されるか?」といった検証が網羅的に行えます。
—
6. まとめ
Terraform 1.6および1.7で進化した `terraform test` フレームワーク、いかがでしたでしょうか?
1. `tests/.tftest.hcl` にHCLでテストが書ける(新しい言語を覚える必要なし!)
2. `mock_provider` を使えば、クラウド環境なしで爆速&無料テストが可能
3. `assert` と `expect_failures` で、正常系も異常系も完璧にカバー
今まで「インフラのテストは面倒くさい、時間がかかる」と諦めていた方にこそ、ぜひ使っていただきたい機能です。
これを日々の開発フローに取り入れるだけで、コードの品質は劇的に向上し、レビューの負担も激減しますよ。
まずは今日作った小さな「Hello World」テストを、あなたのプロジェクトにも導入してみてくださいね。応援しています!