Terraform Testing Matrix
This guide covers choosing testing depth proportional to risk and cost for Terraform and OpenTofu modules.
Testing Layers
- Static checks: format, validate, lint, security scan
- Plan checks: reviewed execution intent
- Native tests: module-level assertions (
terraform test/tofu test) - Integration tests: ephemeral apply + live assertions
- Terratest: workflow/system validation in Go for complex scenarios
Tier A: All Changes (Minimum)
Required for every change:
fmt -checkinit -backend=false+validate- Lint + security scan
- Reviewed plan artifact
Use for low-risk isolated updates.
Tier B: Shared Modules and Medium-Risk Changes
Add on top of Tier A:
- Native test runs for module behavior
- Targeted integration apply tests in ephemeral environment
- Policy checks on plan JSON
Typical triggers:
- Shared module changes
- IAM/network updates
- Encryption/data-boundary updates
Tier C: High-Risk Production Changes
Add on top of Tier A + B:
- Staged rollout (dev -> stage -> prod)
- Rollback rehearsal or documented rollback proof
- Manual owner approvals + security/compliance sign-off
- Post-apply drift detection
Typical triggers:
- State backend migration
- Major refactor with address changes
- Foundational platform stack changes
Native Test Guidance
When to Use command = plan
- Input validation
- Static contract checks
- Argument shape assertions not relying on computed runtime values
When to Use command = apply
- Computed attributes known only after creation
- Assertions over provider-populated fields
- Set/list semantics unresolved in plan stage
Frequent Pitfalls
- Asserting unknown values in plan mode
- Indexing set-type blocks directly
- Assuming mocked providers equal integration confidence
Terratest Guidance
Use Terratest when native tests are insufficient:
- Cross-module workflows
- External API verification (health checks, connectivity)
- Failover/disaster-recovery scenarios
- Multi-step lifecycle tests (apply-change-destroy)
Terratest Test Pyramid
- Fast: contract tests (mocked or plan-level)
- Medium: environment integration tests (ephemeral)
- Slow: limited end-to-end smoke tests for critical paths
Cost Controls
- Tag tests by class (
unit,integration,destructive) - Parallelize only isolated stacks
- Auto-clean resources with TTL tags
- Run expensive tests nightly and on protected branches
Test Framework Scaffolding
.
test/
terratest/
go.mod
helpers/
examples/
network_test.go
native/
main.tftest.hcl
Makefile
Minimal Makefile targets:
test-native:
terraform test
test-terratest:
go test ./test/terratest -timeout 45m
Example Command Flow
terraform fmt -check
terraform init -backend=false
terraform validate
terraform plan -out=plan.bin
terraform show -json plan.bin > plan.json
conftest test plan.json --policy policy/
terraform test
Terratest stage:
go test ./test -run TestCriticalPath -timeout 45m
Quick Selection Rules
| Change Type | Testing Tier |
|---|---|
| Tiny tag change in isolated stack | Tier A |
| Module contract change | Tier A + Tier B |
Refactor with moved and shared impact |
Tier A + B + targeted Terratest |
| Production identity/network/encryption/state changes | Tier A + B + C + Terratest smoke |
Done Criteria
Not done until:
- Required tier passes
- Reviewed plan is approved
- Apply path is trusted and auditable
- Evidence artifacts are retained