How it works
The explanation, with examples you can run.
The cheap layer
terraform fmt -check -recursiveterraform init -backend=falseterraform validatevalidate printed Success! The configuration is valid. for the demo configuration. It catches typos in references, wrong types and missing required arguments. Add a linter such as TFLint for provider-specific mistakes (an instance type that does not exist).
terraform test
Test files (*.tftest.hcl, Terraform 1.6+) contain run blocks. Each run plans or applies the module under test with given variables and checks assert conditions; applied resources are destroyed at the end.
# tests/main.tftest.hclvariables { env = "dev"} run "default_has_two_replicas" { command = plan assert { condition = length(random_pet.service) == 2 error_message = "expected two replicas by default" }} run "names_carry_the_env_prefix" { command = apply variables { env = "prod" replicas = 3 } assert { condition = alltrue([for n in output.names : startswith(n, "prod-")]) error_message = "every name should start with prod-" }} run "rejects_unknown_env" { command = plan variables { env = "qa" } expect_failures = [var.env]}Against a module with a validated env variable and count = var.replicas (Terraform 1.16.6):
tests/main.tftest.hcl... in progress run "default_has_two_replicas"... pass run "names_carry_the_env_prefix"... pass run "rejects_unknown_env"... passtests/main.tftest.hcl... tearing downtests/main.tftest.hcl... pass Success! 3 passed, 0 failed.command = plan tests need no real resources. For providers that would call a cloud, mock providers and overrides (Terraform 1.7+) return fake values, so module logic can be tested in CI without credentials. Real apply tests against a sandbox account catch what mocks cannot (permissions, API constraints), at the cost of time and money.
Conditions in the configuration
- Variable validation rejects bad input before planning.
- Preconditions and postconditions in
lifecycleassert facts about resources and data sources, and fail the run. - check blocks (1.5+) assert on the live system and only warn. In the demo, a check on a port range produced:
Warning: Check block assertion failed on main.tf line 59, in check "port_in_range": 59: condition = random_integer.port.result < 8400 ├──────────────── │ random_integer.port.result is 8443 Port 8443 is in the reserved upper range.Policy on the plan
terraform plan -out=tfplan && terraform show -json tfplan > plan.json produces the full plan as JSON. Policy engines evaluate it: Open Policy Agent (with Conftest), HashiCorp Sentinel in HCP Terraform, or scanners such as Checkov and Trivy. Typical rules: no security group open to the world on port 22, every bucket encrypted and private, no deletes of resources tagged critical, only approved instance types. Failing the pipeline on these makes the rules real, rather than a wiki page.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.