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.
In this article, we will see how to use Terraform test framework with a real world usage.
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
As we are using a Terraform module that relies on AWS cloud provider, the first block the first step will be to insert the
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
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.
create_private_bucket_with_acl will create a new bucket and only test an
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, │ 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.
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:
» 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.