How to use Terraform test

Earlier this month, I've talked about how Terraform test framework is a notable feature that will empower any DevOps to easily test his Terraform code.

Terraform test
After several months of development, Hashicorp unveiled Terraform version v1.6.0 on October 4, 2023. While this isn’t a major release, it introduces a notable feature: the terraform test command. In reality, this goes beyond just a command; it’s an entire framework. The dark age of infrastructure…

In this article, we will see how to use Terraform test framework with a real world usage.

The project

I'll demonstrate the simplicity of adding Terraform tests to legacy code using a community project by Anton Babenko: terraform-aws-s3-bucket. This Terraform module lets you create an S3 bucket with just a few parameters.

I'm now going to craft a test that aims to verify a specific module feature: the creation of a private bucket using an ACL.

Creation of a basic test

First, we need to create the test file itself. You are free to choose the name you want, but it must be suffixed by .tftest.hcl

As we are using a Terraform module that relies on AWS cloud provider, the first block the first step will be to insert the provider block:

To use this module, some variables are required. We will now add a global variables block. Values of this global block can be used across all run blocks (we will see that in the next steps):

We can now create the first test, using a run block. This test will target the current code as a module (like a real end user will do), using the values of the global variables block:

By default, each run block executes with command = apply instructing Terraform to execute a complete apply operation against your configuration. The line 13 set explicitly the default behaviour for training purpose, you can remove it if you want.

The run block create_private_bucket_with_acl will create a new bucket and only test an apply / destroy workflow.

Let's create a unit test check_private_bucket_with_acl that check if the bucket name match the variable value:

Now, let's run the test!

» terraform init
Initializing the backend...
Initializing modules...
- test.basic.create_private_bucket_with_acl in .

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v5.21.0...
- Installed hashicorp/aws v5.21.0 (signed by HashiCorp)

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

» terraform test
basic.tftest.hcl... in progress
  run "create_private_bucket_with_acl"... fail
╷
│ Error: expected length of bucket_prefix to be in the range (0 - 37), got demo-hashicorp-terraform-test-captaincy
│ 
│   with aws_s3_bucket.this[0],
│   on main.tf line 29, in resource "aws_s3_bucket" "this":
│   29:   bucket_prefix = var.bucket_prefix
│ 
╵
  run "check_private_bucket_with_acl"... skip
basic.tftest.hcl... tearing down
basic.tftest.hcl... fail

Failure! 0 passed, 1 failed, 1 skipped.

The test is working, it shown that the value of the variable `bucket_prefix` is to long. Let's change it and retry:

 » terraform test                                            1 ↵
basic.tftest.hcl... in progress
  run "create_private_bucket_with_acl"... pass
  run "check_private_bucket_with_acl"... pass
basic.tftest.hcl... tearing down
basic.tftest.hcl... pass

Success! 2 passed, 0 failed.

Testing failures

By default, check block assertions fail during the execution of a Terraform test file then the overall command reports the test as a failure.

However, it is a common testing paradigm to want to test failure cases. Terraform supports the expect_failures attribute for this use case.

Back to our module, I want to support only two types of ACL rather that the full list: "private" and "public-read" (removing usage of "public-read-write", "authenticated-read", "aws-exec-read" and "log-delivery-write"). I will now modify the variable block "acl" to add this condition:

Let's create a new test check_acl_type to check the variable validation:

Execution:

» terraform test
basic.tftest.hcl... in progress
  run "check_acl_type"... pass
  run "create_private_bucket_with_acl"... pass
  run "check_private_bucket_with_acl"... pass
basic.tftest.hcl... tearing down
basic.tftest.hcl... pass

Success! 3 passed, 0 failed.

Lenstra helps companies leverage Computer Science to enhance their Economic Performance

Contact us for a free consultancy to explore how we can work together.

Contact us

Read more