Writing Terraform Tests With AI Without Faking the Coverage
AI can churn out Terraform native test files fast, but most of what it writes tests nothing. Here is how to get assertions that would actually catch a regression.
- #terraform
- #ai
- #testing
- #tflint
When terraform test landed as a native feature, I did what everyone does with a new toy: asked an AI to generate tests for an existing module. Thirty seconds later I had a tests/ directory full of .tftest.hcl files and felt great about myself. Then I read them. Half the assertions checked that a value I’d just set equalled the value I’d just set. That’s not a test. That’s a tautology with extra steps.
AI is genuinely useful for Terraform testing, but only if you understand its failure mode: it writes tests that pass, not tests that catch bugs. Like a junior engineer chasing a coverage number, it’ll happily assert the obvious. Your job is to direct it at the things that actually break.
The tautology problem
Here’s the kind of test the AI loves to write unprompted:
run "bucket_name_is_set" {
command = plan
assert {
condition = aws_s3_bucket.this.bucket == var.bucket_name
error_message = "Bucket name should match input"
}
}
If your module is bucket = var.bucket_name, this assertion can never fail unless Terraform itself is broken. It tests the framework, not your logic. Coverage tools count it; reality doesn’t. The fix is to point the AI at behavior derived from inputs, not pass-through values.
Ask for tests of the logic, not the wiring
The interesting parts of a module are where it transforms inputs: conditionals, for expressions, computed names, validation. Prompt for those:
Look at this module. Identify every place where an output or resource attribute is computed from inputs (conditionals, string interpolation, for_each keys). Write a
terraform testrun block for each that would fail if the logic were wrong. Skip anything that’s a direct pass-through.
Now you get something worth running. Say the module builds a name from environment and region:
run "name_includes_env_and_region" {
command = plan
variables {
name = "api"
environment = "prod"
region = "us-east-1"
}
assert {
condition = aws_s3_bucket.this.bucket == "api-prod-use1"
error_message = "Computed bucket name format changed unexpectedly"
}
}
That assertion encodes a real expectation. If someone “tidies up” the locals and drops the region abbreviation, this test goes red. That’s the whole point.
Make it test the failure paths
The highest-value tests in Terraform are the ones that confirm bad input is rejected. AI rarely writes these unless you demand it, because the prompt “test this module” implies happy-path. Use expect_failures:
run "rejects_invalid_environment" {
command = plan
variables {
environment = "production" # should be "prod"
}
expect_failures = [
var.environment,
]
}
Prompt: “For every validation block in this module, write a test that supplies an invalid value and asserts the validation fires.” This pairs beautifully with the validation blocks themselves — and it’s exactly the boring, exhaustive work a fast junior engineer should do while you review the list for completeness.
Pro Tip: Ask the AI to write one test that uses command = apply against a throwaway resource and one that uses command = plan. plan tests are fast and run everywhere; apply tests catch provider-side failures but cost real resources and credentials. Default to plan and reserve apply for the handful of cases that need it.
Don’t let it invent helper modules you don’t have
A recurring AI mistake: it references a setup module or a fixture file that doesn’t exist in your repo, because some training example had one. Native tests support run blocks that call helper modules:
run "setup" {
module {
source = "./tests/setup"
}
}
If ./tests/setup isn’t real, every test errors out before asserting anything. Always diff the AI’s test files against your actual directory structure. The model hallucinates fixtures the same way it hallucinates function names.
Wire it into CI as a gate, not a vibe
Generated tests are worthless if nobody runs them. The point of terraform test is to block a bad merge:
terraform init -backend=false
terraform test
-backend=false keeps plan-only tests from needing real backend access — which is exactly the posture you want for AI-adjacent work. The model wrote the assertions; CI runs them; no credentials handed to anything that doesn’t strictly need them.
You can layer static checks underneath, too. tflint and terraform validate catch a class of problems before tests even run, and they’re free:
terraform validate && tflint --recursive
Ask the AI to suggest custom tflint rules for your org conventions — but, again, review them. A linter rule that’s wrong is just noise that trains people to ignore CI.
The boundary stays the same
The AI writes test files. It does not run terraform apply against prod, it does not hold cloud credentials, and it does not get write access to state. Tests are one of the safest AI surfaces precisely because they live as reviewable HCL and run in an isolated CI context. Keep the model on the writing side of the wall. A junior engineer who drafts tests is great; one with the apply button is a liability.
For ready-made testing prompts, see the prompts library and prompt packs. You can also push generated test files through the code review dashboard for a first automated pass, and browse more in AI for Terraform.
Conclusion
A directory full of green tests means nothing if the assertions are tautologies. Aim the AI at computed logic and failure paths, make it write expect_failures cases for every validation, and diff its fixtures against reality. The model is a fast junior engineer who’ll happily hit a coverage number — you’re the senior who makes sure the tests would actually catch the next regression.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.