.tftest.hcl files and terraform test. You have all the
prerequisites: plan vs apply (lessons 1, 6), unknown-until-apply values, and modules as the
unit worth testing (lesson 4).
A test file is HCL: run blocks that execute your configuration and
assert on the result. The entire skill of Terraform testing is knowing
what each mode can see: plan-mode sees logic, apply-mode sees reality, mocks see your
wiring but fake the world.
# tests/naming.tftest.hcl — discovered automatically by `terraform test` variables { prefix = "acme" } # inputs for every run in this file run "name_composes" { command = plan # unit-style: fast, free, nothing created variables { env = "dev" } assert { condition = aws_s3_bucket.b.bucket == "acme-dev-logs" error_message = "name did not compose" } } run "rejects_bad_env" { command = plan variables { env = "prod!!" } expect_failures = [var.env] # asserts the validation REJECTS this }
run blocks execute in order, sharing state within a file — later runs can
read earlier runs' outputs (run.setup.bucket_arn): setup → exercise → assert, in pure HCL.
apply. A run block without
command = plan executes a full, real apply — real resources, real money, real IAM.
Terraform auto-destroys them when the file finishes, but a crashed test run can strand them.
Treat a bare run block in review exactly like an apply in review.
mock_provider "aws" {} swaps the real provider for a fake: command = apply
then "creates" resources instantly, with generated placeholder values for computed
attributes (ARNs become random strings). Pin the ones your logic needs with
override_resource / override_data.
What mocks test: your composition, conditionals, and wiring. What they can't test: whether AWS accepts it. A mocked test can pass while the real apply fails on a real IAM policy.
That gives you a pyramid: static (validate, fmt — seconds) → unit
(plan-mode + mocks — seconds, every push) → integration (real apply in a sandbox account —
minutes and money, nightly or pre-release). Same economics as software testing.
env with a validation block
(allow only dev/stage/prod), and a local that composes "acme-${var.env}-logs"
into a terraform_data (or mocked aws_s3_bucket) name.tests/naming.tftest.hcl with the two runs from above (adapted), and run
terraform test.mock_provider "aws" {} and try a command = apply
run with no credentials.