Write .tftest.hcl files next to the module, use command = plan for fast checks that create nothing, and use command = apply sparingly for integration checks that build real, short-lived resources. Run them in CI on every pull request to the module repository.
What the framework is
HashiCorp states the terraform test framework is available in Terraform v1.6.0 and later. Test files use the .tftest.hcl or .tftest.json extension. Each file has one or more run blocks, executed in order by default, and each simulates Terraform commands against the configuration directory.
Each run block sets command to plan or apply, and apply is the default. Assertions are assert blocks with a condition and an error_message, and a failed assertion fails the test.
Plan or apply
command = plan | command = apply | |
|---|---|---|
| Creates infrastructure | No | Yes, short lived |
| Speed | Fast | Slower |
| Closest analogy | Unit test | Integration test |
| Good for | Validation rules, naming, defaults | Behaviour that needs real resources |
HashiCorp notes that apply tests create real resources by default and Terraform destroys them when the test file finishes. That means credentials with permission to create and delete. Use a dedicated test account with tight limits, not a production one.
Mocked provider data was introduced in v1.7.0, which supports more detailed unit tests without calling a cloud API. Use mocks when you want to check logic, not provider behaviour.
What to test in a shared module
- Interface stability. Assert that expected outputs exist, so renaming one is caught before release.
- Validation rules. Run once with a good value and once with a bad one, expecting failure. See variable validation guardrails.
- Secure defaults. Assert that default inputs yield the safe setting, such as encryption enabled.
- Conditional resources. Check that toggles create or skip the resources you expect.
- Upgrade path. Keep a test that applies the previous release's example, then plans the new one, to see whether anything would be replaced.
The last item is a team convention, not a framework feature, and it is the one that most protects callers.
Running it in CI
Run plan based tests on every pull request. Run apply based tests on a schedule or before tagging a release, because they cost money and time. Make the test job a required status check so a failing test blocks the merge. See branch protection rules worth enabling.
Keep test credentials short lived. Deploying from GitHub Actions with OIDC avoids stored keys.
Limits
A passing test shows that the module behaves as you asserted. It does not prove the configuration is secure, because you only assert what you thought of. Tests complement review and scanning, they do not replace them.
Where Safeguard fits
Safeguard can gate pull requests with policies and keep evidence that checks ran before a change merged. Test design remains the module author's job.
Quick check
Does terraform test destroy what it creates?
By default, apply based tests create real resources and Terraform destroys them when the test file finishes, per HashiCorp. Check for leftovers after a failed run.
Which Terraform version do I need?
Version 1.6.0 or later for the test framework, and 1.7.0 or later for mocked providers.
Sources
Last reviewed: 19 October 2026.