A Terraform testing framework provides a Terraform-centric safety net for modules, helping developers review pull requests and detect breaking changes despite infrastructure-testing costs such as long runtimes and orphaned resources. section 9.7
Its distinctive model is direct access to module state: a test can use a full resource path to inspect resources, data sources, and local variables after execution. Terratest instead wraps Terraform externally, so it cannot validate internal state in the same way. section 9.4.2
Listing 9.22 Accessing named values
variables {
test_input = "test"
}
run "input_passed_to_resource" {
assert {
condition = terraform_data.this.input == "test" #1
error_message = "The resource parameter does not match the input."
}
}
A named-value assertion checks that an input reaches a resource, demonstrating direct inspection of a module's internal value. section 9.4.2
Use the framework with these operational patterns:
- Place tests beside examples when examples serve as test cases; each example then requires initialization and a local terraform test invocation. section 9.4.4
- Automate coverage with make terraform_test, which iterates through example directories, initializes without a backend, and runs each test. section 9.4.4
- Treat Terraform and the testing framework as one versioned unit: switching Terraform or OpenTofu changes the framework version and available features. section 9.4.5
- Account for compatibility limits: framework features may prevent testing older Terraform versions, while supported-version requirements force use of the lowest common feature set. section 9.4.5
Listing 9.28 The module block
TERRAFORM_EXAMPLES:=$(wildcard examples/*) #1
TF_TEST_OPTS:=
.PHONY: $(TERRAFORM_EXAMPLES) #2
$(TERRAFORM_EXAMPLES): #3
@echo "Testing $@" #4
cd $@ && \ #5
$(TF_BINARY) init -backend=false && \ #6
$(TF_BINARY) test $(TF_TEST_OPTS) #7
.PHONY: terraform_test
terraform_test: $(TERRAFORM_EXAMPLES) #8
@echo "Testing Root Module"
$(TF_BINARY) test $(TF_TEST_OPTS) #9
A Makefile can discover example directories and provide one aggregate target while retaining direct targets for individual example tests. section 9.4.4
Listing 9.29 makefile support
TERRAFORM_VERSION:=$(shell cat .terraform-version) #1
TOFU_VERSION:=$(shell cat .terraform-version) #2
TF_ENGINE:=terraform #3
ifeq ($(TF_ENGINE), terraform) #4
TF_BINARY:=terraform
TF_VERSION:=$(TERRAFORM_VERSION) #5
else ifeq ($(TF_ENGINE), opentofu)
TF_BINARY:=tofu
TF_VERSION:=$(TOFU_VERSION) #6
endif
ifeq ($(CI), ) #7
TF_ENV_COMMAND:=tenv use $(TF_BINARY) $(TF_VERSION)
else #8
TF_ENV_COMMAND:=echo "skipping tenv use in CI"
endif
TERRAFORM_EXAMPLES:=$(wildcard examples/*)
TF_TEST_OPTS:= #9
.PHONY: $(TERRAFORM_EXAMPLES)
$(TERRAFORM_EXAMPLES):
@echo "Testing $@"
cd $@ && \
$(TF_ENV_COMMAND) && \ #10
$(TF_BINARY) init -backend=false && \
$(TF_BINARY) test $(TF_TEST_OPTS)
.PHONY: terraform_test_root
terraform_test_root: #11
@echo "Testing Root Module"
$(TF_ENV_COMMAND) && \ #12
$(TF_BINARY) test $(TF_TEST_OPTS)
.PHONY: terraform_test #13
terraform_test: $(TERRAFORM_EXAMPLES) terraform_test_root #14
Version-aware Makefile support selects Terraform or OpenTofu, coordinates tenv locally, and skips local version switching in CI. section 9.4.5



