Learning objectives
By the end of this module, you should be able to:
- Choose between input validation, preconditions/postconditions and check blocks.
- Understand that failing check blocks warn rather than block the operation.
- Write and execute a provider-free terraform test.
Different validations run at different boundaries
Variable validation checks module inputs. Preconditions and postconditions enforce assumptions/guarantees around resources, data sources and outputs. They can block execution when conditions fail.
check blocks support continuous assertions
check blocks run after plan/apply validation and report warning diagnostics when assertions fail rather than blocking the operation. They are useful for ongoing infrastructure checks.
terraform test executes test files in isolated state
terraform test runs .tftest.hcl test files and uses state separate from the normal working state. Tests can plan or apply and make assertions. Tests that create real infrastructure can incur cost, so test accounts and cleanup matter.
Worked examples
See the idea in practice.
Provider-free Terraform test
// tests/name.tftest.hcl
run "name_contract" {
command = plan
variables {
environment = "prod"
}
assert {
condition = output.name == "APP-PROD"
error_message = "unexpected name"
}
}
- The test can validate root-module behavior without touching the normal state.
Hands-on lab
Lab — Add executable Terraform tests
Goal: Validate an input contract and output transformation with terraform test.
Before you start
- Terraform 1.6+ is required for the stable terraform test workflow used here.
STEP 1Create tested configuration
mkdir -p ~/gnu-terraform-labs/module10/tests && cd ~/gnu-terraform-labs/module10
cat > main.tf <<'EOF'
variable "environment" {
type = string
validation {
condition = contains(["dev", "prod"], var.environment)
error_message = "use dev or prod"
}
}
output "name" {
value = upper("app-${var.environment}")
}
EOF
STEP 2Write test file
cat > tests/name.tftest.hcl <<'EOF'
run "name_contract" {
command = plan
variables {
environment = "prod"
}
assert {
condition = output.name == "APP-PROD"
error_message = "unexpected name"
}
}
EOF
STEP 3Initialize
terraform init
STEP 4Run tests
terraform test
Verify
- The test run passes.
- The normal working state is not required for the test.
Expected outcome
- Infrastructure expectations are executable and can run in CI.
If it fails
- terraform test can create real resources when tests use apply; isolate credentials and accounts accordingly.
- A check block failure is a warning; use blocking validation when a failed invariant must stop the operation.
Real-world connectionModule tests and validation reduce regression risk before infrastructure changes reach production plans.
Avoid these traps
Common mistakes
- Assuming check assertion failures block apply.
- Running destructive module tests against production accounts.
- Testing only syntax while ignoring behavioral outputs and invariants.
Knowledge check
Can you explain it without looking back?
Open each answer only after you have tried to answer the question yourself.
1Does a failing check block stop an apply?
No; it reports a warning and continues the operation.
2What can terraform test execute?
Plan or apply test runs with assertions using isolated test state.
3When is variable validation appropriate?
When an invalid module input should be rejected before infrastructure operations proceed.