How to test your Terraform code
Learn about the HashiCorp Terraform Module Testing Experiment configuration and how to use it to run tests against infrastructure.

Testing is vital to understand if the infrastructure code we created is doing what they are supposed to. Running a terraform plan
helps, but it’s not a guarantee. The best way is to deploy the resources in a controlled manner.
Terratest and kitchen-terraform both pioneered the idea of writing tests for Terraform modules with explicit orchestration written in the Go and Ruby programming languages, respectively.
Since Terraform CLI v0.15.0 Hashicorp introduced an experimental testing module, this is what I’d like to talk about it.
Writing Tests for a Module
I’ll use a Terraform code that creates buckets in GCP as the source. You can find the code in this GitHub repository and a detailed explanation in this Medium article.
I want to test whether the Terraform is creating a bucket. So, my test will be to create a bucket and verify the execution by comparing the bucket’s name.
First, configure the outputs.tf
file to output the bucket name:
output “bucket_name” {
value = google_storage_bucket.bucket.name
}
Second, make sure your variables.tf
has a default value assigned to each variable.
Third, within the terraform-google-cloud-storage/cloud-storage-module
create a new sub-folder tests/defaults
. In the defaults
directory, create a defaults.tf
file.
The tests/defaults/defaults.tf
file will contain a call to the main module with a suitable set of arguments and resources that will, for the sake of the experiment, serve as the temporary syntax for defining test assertions. For example:
module "main" {
# source is always ../.. for test suite configurations,
# because they are placed two subdirectories deep under
# the main module directory. source = "../.." # This test suite is aiming to test the "defaults" for
# this module, so it doesn't set any input variables
# and just lets their default values be selected instead.
}
The following code is the test assertion configuration:
# The special test_assertions resource type, which belongs
# to the test provider we required above, is a temporary
# syntax for writing out explicit test assertions.resource "test_assertions" "bucket" {
# "component" serves as a unique identifier for this
# particular set of assertions in the test results. component = "bucket" equal "bucket_name" {
description = "default bucket_name is natali-test-eu-627"
got = module.main.bucket_name # value from the output
want = "natali-test-eu-627"
}
}
In the equal
block, I’m comparing the bucket name that the main module outputted (got
) with the value I defined in the variables.tf (want
). If they match, the test ran successfully.
Running the tests
The terraform test
command is an experimental command to help with automated integration testing of shared modules. Terraform operations similar to the following sequence of commands:
terraform validate
terraform apply
terraform destroy
In this example, navigate to the terraform-google-cloud-storage/cloud-storage-module
folder and execute terraform test
:
$ terraform test
Success! All of the test assertions passed.
To force an error, I change the want
value in the test without changing the value in the variables.tf
────────────────────────────────────────────────────────
Failed: defaults.bucket.bucket_name
(default bucket_name is natali-test-eu-627) ────────────────────────────────────────────────────────
wrong value
got: "natali-test-eu-627"
want: "natali-test-eu-628"
Known Limitations
As an experimental module, there are a few limitations on how it works. At the time of writing (March, 2022) the two main limitations I’d like to highlight are:
- Currently tests written in this way can only exercise the create and destroy behaviours.
- Unit testing without creating real objects. You cannot test against non-real resources.
Please, refer to the Hashicorp documentation for a complete list.