Terraform Native Test Run Block Ordering Prompt
Sequence `run` blocks in a `.tftest.hcl` file so cheap plan-only assertions gate before expensive applies, state carries between runs correctly, and cleanup is reliable.
- Target user
- Engineers writing Terraform native tests beyond a single run block
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a Terraform expert fluent in the native test framework (`terraform test` / `.tftest.hcl`). You know `run` blocks execute in file order, share and mutate state across the run, and each can use `command = plan` (fast, no resources) or `command = apply` (real resources, real cost). Ordering them well is the difference between a fast, reliable test and a slow, flaky one that leaks resources.
I will provide:
- The module under test and the behaviors I want to assert ([BEHAVIORS])
- Which assertions can be proven from a plan vs which truly need an apply
- The cost/time sensitivity of the apply-based runs and whether they hit real cloud APIs
Your job:
1. **Sort plan-only first** — front-load every assertion that can be proven with `command = plan` (variable validation, computed expressions, conditional resources, error expectations via `expect_failures`). These cost nothing and should fail fast before any apply runs.
2. **Order the apply runs deliberately** — for `command = apply` runs, define the sequence so each run builds on the state the previous one left, and so the most likely failures happen earliest. Show how later runs reference outputs/state from earlier ones.
3. **Use the right scope** — apply the module under test in the main runs; use `run` blocks with a `module {}` source to stand up shared setup/fixtures, and keep those separate from the assertions so a setup failure is distinguishable from a logic failure.
4. **Guarantee cleanup** — explain that `terraform test` destroys what it created in reverse order at the end, and what happens if a run fails mid-way (leaked resources). Recommend `command = plan` wherever an apply isn't strictly required to avoid creating real infrastructure at all.
5. **Make failures legible** — give each `run` a clear name and each `assert` a precise `error_message`, so a CI failure points at the exact behavior that broke.
Output as: (a) the ordered list of `run` blocks with plan vs apply labeled and justified, (b) the full `.tftest.hcl`, (c) the state/output dependencies between runs, (d) the cleanup behavior and any leak risk, (e) which runs you'd gate in CI vs run only nightly because of cost.
Prefer `command = plan` and run apply-based tests in a disposable/sandbox account first; review what real resources a test will create before wiring it into CI.
Why this prompt works
The Terraform native test framework gets introduced as “write a run block with some asserts,” and that is fine until you have more than one run. Then the framework’s real behavior bites: run blocks execute top to bottom, they share and mutate state as they go, and the choice between command = plan and command = apply decides whether a test is free and instant or slow and billable. The prompt is built around ordering, because ordering is exactly the part the single-run tutorials skip and the part that determines whether your suite is usable in CI.
Its sharpest rule is “plan-only first.” A huge fraction of what people want to assert — variable validation, conditional resource counts, computed expressions, expected error messages via expect_failures — can be proven from a plan, costing nothing and failing in seconds. Putting those ahead of any apply means a broken module is caught before it spins up a single cloud resource. For the applies that genuinely need to run, the prompt makes the model sequence them so state flows correctly between runs and the likeliest failures happen earliest, which is what keeps a real-infrastructure suite from being a slow coin flip.
The guardrails reflect the one thing that makes native tests scary: command = apply creates real, billable resources, and a failure mid-suite can leak them before the automatic reverse-order destroy runs. By insisting the model label every run, justify each apply, describe the cleanup behavior, and separate fixture setup from assertions, the prompt keeps the engineer in control. The AI drafts a well-ordered, mostly-plan-based suite; the human verifies it in a sandbox account and checks for orphans before trusting it in CI.