How do you test Terraform code (terratest, terraform test, plan assertions)?
Quick Answer
Test Terraform code at three levels: static analysis with terraform validate and tflint, integration testing with the native terraform test framework (HCL-based tests that run plan or apply against real infrastructure), and end-to-end testing with Terratest (Go-based framework that provisions infrastructure, validates it, and tears it down). Use plan assertions to verify expected changes without applying.
Detailed Answer
Testing Terraform code requires a layered approach because infrastructure code has fundamentally different risk profiles than application code. Think of it like testing a building design: you have blueprint reviews (static analysis), structural simulations (plan-based testing), scale model tests (integration tests in isolated accounts), and the final building inspection (end-to-end tests against real infrastructure).
The first layer is static analysis, which catches errors without any provider interaction. terraform validate checks HCL syntax and basic type errors. terraform fmt -check enforces consistent formatting. tflint goes further with provider-aware linting: it can detect invalid instance types (aws_instance with instance_type = 'm5.huuge'), deprecated resource arguments, and naming convention violations. Custom tflint rules can enforce organizational standards. Checkov and tfsec scan for security misconfigurations: public S3 buckets, unencrypted databases, overly permissive security groups. These tools run in seconds and belong in pre-commit hooks and CI pipeline early stages.
The second layer is plan-based testing, which runs terraform plan and asserts on the planned changes without actually modifying infrastructure. The native terraform test framework (introduced in Terraform 1.6) allows writing tests in HCL files with .tftest.hcl extension. Each test file defines variables, runs plan or apply commands, and asserts on outputs or resource attributes. Plan-mode tests are fast and safe: they verify that your configuration produces the expected plan without touching real infrastructure. You can assert that specific resources will be created, that computed values match expectations, and that no unexpected destroys are planned.
The third layer is integration testing with terraform test in apply mode or with Terratest. Terraform test in apply mode provisions real infrastructure in an isolated test account, runs assertions against the live resources, and destroys everything afterward. Terratest (a Go library by Gruntwork) provides more flexibility: you can make HTTP requests to deployed endpoints, run SQL queries against provisioned databases, SSH into EC2 instances to verify configuration, and use retry logic for eventually consistent resources.
Terratest's power comes from Go's testing ecosystem. You write Go test functions that call terraform.InitAndApply, then use AWS SDK calls to validate the infrastructure matches expectations. For example, after deploying an RDS cluster, you can use the AWS SDK to verify encryption is enabled, multi-AZ is configured, and the parameter group has the expected settings. The test function calls terraform.Destroy in a deferred cleanup block.
Production gotchas for Terraform testing include: test account isolation is critical because integration tests create real resources with real costs. Use AWS Organizations with a dedicated testing account and service control policies to prevent tests from accessing production. Implement cost controls with AWS Budgets on test accounts. Parallelize tests carefully because Terraform state conflicts can occur if multiple test runs target the same state backend. Use unique naming prefixes or workspaces per test run. Terraform test has limitations with provider mocking (experimental in 1.7) and cannot easily test cross-module interactions. Terratest requires Go proficiency and has slower test execution times due to real infrastructure provisioning. A balanced strategy uses static analysis in pre-commit hooks, plan assertions in CI, and full integration tests nightly or before releases.