Testing in infrastructure as code using Terraform is crucial for ensuring that changes to infrastructure are correct, safe, and up to expected standards before applying them to live environments. This process helps to prevent costly mistakes and disruptions, resulting in more reliable, stable, and secure infrastructure. By running tests, we can verify that the infrastructure changes made through Terraform are working as intended, without any unintended consequences. Understanding what is Terraform and how it operates is essential for effectively managing infrastructure as code.
Different Types of Terraform Tests
1. Unit Tests
Unit tests focus on specific components or modules of infrastructure configurations. These tests validate individual units of related code, ensuring they work correctly. In the context of Terraform, unit tests can help verify that modules are functioning as expected and that any changes do not introduce breaking changes.
2. Integration Tests
Integration tests check how different modules, components, or infrastructure configurations interact with each other. These tests help ensure that all parts of the infrastructure work well together and that the changes in one component do not negatively impact others.
3. End-to-End Tests
End-to-end tests validate the entire infrastructure setup as a whole. These tests check if the infrastructure behaves as expected from the viewpoint of the end-user or the application it supports. Running end-to-end tests is essential to confirm that the overall infrastructure meets the desired functionality and requirements.
Using Terraform Test Framework
The Terraform test framework, introduced in Terraform 1.6, provides an automated way to conduct unit and integration tests for Terraform configurations and modules. This framework uses the HCL syntax, familiar to Terraform users, making it easy to write tests for infrastructure changes. Authors can run these tests against temporary resources, mitigating risks to existing infrastructure or state.
Integration or Unit Testing in Terraform
Terraform tests create real infrastructure by default, allowing users to validate Terraform's core functions and operations. This method is similar to integration testing, where infrastructure is created and validated.
Users can override the default behavior and perform unit testing by specifying that Terraform should not create new infrastructure during testing. This allows for testing logical operations and custom conditions without altering the infrastructure. Terraform v1.7.0 introduced the ability to simulate provider data during test execution, aiding in writing more detailed unit tests.
Syntax and Execution of Terraform Tests
Each Terraform test file must have a .tftest.hcl or .tftest.json extension, and it typically contains run blocks, variables blocks, and provider blocks. The run blocks are executed in order, simulating Terraform commands in the configuration directory. Variables and provider blocks are processed at the beginning of the test operation, and the order of these blocks does not matter. By organizing the variables and providers first, users can streamline the testing process and create more efficient tests.
Related Reading
Example of a Terraform Test File
Here's an example of a Terraform test file that verifies the creation of an AWS S3 bucket with a specific name:
In the test file `valid_string_concat.tftest.hcl`, we verify that the bucket name was created as expected:
In the example above, the test file uses input variables to define the bucket prefix and then checks if the bucket name is correctly created as expected. The run block specifies the command to execute, `plan`, and then defines an assertion to verify if the bucket name matches the expected value. If the condition fails, an error message is displayed.
This is how you can write a Terraform test file to validate the creation of AWS S3 buckets.
Understanding and Utilizing the Terraform Test Command
The Terraform test command is a powerful tool specifically designed to run tests written in Terraform configurations. It reads the test files defined in your configuration files with .tftest.json and .tftest.hcl extensions and executes the tests defined in those files. By default, Terraform will search for these files in the current directory and the specified testing directory (which is typically named 'tests').
Setting Up a Basic Terraform Configuration File for Testing
To set up a basic Terraform configuration file for testing, you can create a file with .tftest.hcl extension. You can define your test blocks that contain the test information. Each test block contains the provider, resource, and configuration block for the test. For example, you can set up a test to verify the creation of a specific AWS S3 bucket.
Executing the Terraform Test Command
To execute the Terraform test command, you need to navigate to the directory where your Terraform configurations are stored and run the command in the terminal. You can also run the terraform test command with optional attributes, such as -test-directory=<directory>, -json, -verbose, or -filter=testfile, to customize your testing operation. For instance, if you want to test only specific files, you can use the -filter attribute.
Zeet for Seamless Cloud Deployments
Zeet helps you to get more from your cloud, Kubernetes, and Terraform investments and helps your engineering team become strong individual contributors through our CI/CD & deployment platform.
Contact Zeet to learn more about how Zeet helps you get seamless cloud deployments every time, and helps your team to become a top-performing engineering team.
How to Perform Effective Unit and Contract Testing in Terraform
Unit Testing in Terraform
Unit testing is a vital aspect of Terraform development. These tests focus on testing each component of the Terraform code individually to ensure they function correctly. This approach allows us to validate each module's logic independently. For example, let's say we have a Terraform module that deploys an AWS S3 bucket. We can write a unit test to confirm that this specific configuration deploys the bucket correctly.
Let me walk you through the process of writing a simple unit test for a Terraform module that creates an AWS S3 bucket. Here's the Python code using AWS CDK for Terraform:
Contract Testing in Terraform
Contract testing ensures that the interaction between different modules in Terraform respects the expected contract. These tests confirm that a configuration using a Terraform module adheres to the correct input format, thus validating the module's intended use. Let's delve into a contract testing example that enforces specific rules for an EC2 instance type:
In this code snippet, we validate the `instance_type` variable to only allow three specific values. This way, contract testing ensures that users adhere to the intended use of the Terraform module.
Related Reading
- Terraform Apply Auto Approve
- Terraform Module
- Terraform vs Cloudformation
- Terraform AWS Security Group
- Terraform Kubernetes Provider
- Terraform AWS Lambda
- Datadog Terraform
- Terraform Cloud Pricing
- Terraform IAM Role
- Terraform Debug
- Terraform Docker
- Github Actions Terraform
- Terraform Import Existing Resources
- Terraform ECS
- DevOps Terraform
- Terraform Automation
- Terraform CI CD
- Terraform Workflow
- Terraform Security
- Terraform Orchestration
- Terraform Multi Cloud
- Terraform No Code Provisioning
- Terraform Migrate State
- Terraform State Management
- Terraform AWS RDS
- What is Terragrunt
- Terragrunt vs Terraspace
- Terraform Multiple Environments
- Terraform Multiple Users
- Upgrade Terraform Version
- Terraform Commands
- Terraform Alternatives
- Terraform Stacks
- Crossplane Vs Terraform
- Terraform Import
- Terraform Tutorial
- Terraform for_each
- Terraform Dynamic Block
Integrating Comprehensive Integration Testing in Terraform Workflows
Integration testing involves testing your entire infrastructure configuration, including any dependencies on other resources, to ensure that they work together correctly. Terraform has built-in dependency mapping and management that can be utilized to make sure the changes being made are as expected.
You can use tools like Terratest or Kitchen-Terraform for integration testing. The following tools can also be used in the workflow, and including them in the CI pipeline will form Integration Testing:
Terraform fmt
To format the code correctly.
Terraform validate
To verify the syntax.
Terraform plan
To verify the config file will work as expected.
TFLint
To verify the contents of the configuration as well as the syntax and structure, also checks account limits (e.g. that a VM instance type is valid, and that the limit on the number of VMs in Azure has not been reached).
Kitchen-Terraform
Kitchen-Terraform is an open-source tool that provides a framework for writing automated tests that validate the configuration and behavior of Terraform code, including testing for errors, resource creation, destruction, and validation of outputs. Kitchen-Terraform uses a combination of Ruby, Terraform, and Test Kitchen to spin up infrastructure in a sandbox environment, run tests, and destroy the infrastructure once testing is complete.
Terratest
Terratest is an open-source testing framework for testing Terraform that can also be used to test Kubernetes, Docker, and Packer, amongst others. Terratest enables automated testing of infrastructure code in a sandbox environment to validate that it meets requirements, functions as expected, and is reliable.
Tests are written in Go, and it provides a rich set of testing functions that allow the user to automate the entire testing process, including provisioning resources, running tests, and cleaning up resources. Terratest also provides built-in support for popular testing frameworks like Ginkgo and Gomega.
How to use Terratest in Terraform Testing
In the Terratest example below, a function is created to test the creation of an Azure storage account in a resource group, and a container in the storage account, then verifies that the storage account and container exist. The resources are then cleaned up after the test is complete.
package test
import (
"context"
"fmt"
"testing"
"time"
"github.com/Azure/azure-sdk-for-go/storage"
"github.com/gruntwork-io/terratest/modules/azure"
"github.com/gruntwork-io/terratest/modules/random"
"github.com/gruntwork-io/terratest/modules/testing"
)
func TestAzureStorageAccount(t *testing.T) {
t.Parallel()
Set the Azure subscription ID and resource group where the Storage Account will be created
uniqueID := random.UniqueId()
subscriptionID := "YOUR_AZURE_SUBSCRIPTION_ID"
resourceGroupName := fmt.Sprintf("test-rg-%s", uniqueID)
Create the resource group
azure.CreateResourceGroup(t, resourceGroupName, "uksouth")
Set the Storage Account name and create the account
accountName := fmt.Sprintf("teststorage%s", uniqueID)
accountType := storage.StandardZRS
location := "uksouth"
account := azure.CreateStorageAccount(t, subscriptionID, resourceGroupName, accountName, accountType, location)
Create a container in the Storage Account
ctx := context.Background()
client, err := storage.NewBasicClient(accountName, azure.GenerateAccountKey(t, accountName))
if err != nil {
t.Fatalf("Failed to create Storage Account client: %v", err)
}
service := client.GetBlobService()
containerName := fmt.Sprintf("testcontainer%s", uniqueID)
if _, err := service.CreateContainer(ctx, containerName, nil); err != nil {
t.Fatalf("Failed to create container: %v", err)
}
Check if the container exists
testing.WaitForTerraform(ctx, terraformOptions, nil)
Cleanup resources
defer azure.DeleteResourceGroup(t, resourceGroupName)
}
End-to-End Testing Strategies for Terraform Deployments
End-to-end testing involves testing the complete functionality of an infrastructure deployment from start to finish. This can be done in a staging environment, and tools like Terratest can be utilized for automated end-to-end testing of infrastructure managed by Terraform.
In the context of Azure storage accounts, end-to-end testing can entail validating the existence of a created Azure Storage account and the correctness of the container's name and access type.
Here's how to implement end-to-end testing with Terraform using Terratest:
1. Create Terraform Configuration
Define an Azure Storage account and container in a Terraform configuration file.
2. Implement Terratest Test
Develop a Terratest test file to deploy the Terraform configuration and verify the created Azure Storage account and container. This test file will access the Azure Storage account and container information using the Azure SDK.
3. Run the Test
Execute the test by navigating to the directory where the test file is saved and running the command 'go test -v'.
The test validates that the Azure Storage account and container were created correctly and have the expected configurations. This end-to-end testing ensures that the infrastructure deployment functions as intended.
Mock Terraform Tests and Best Practices for Efficient Testing
Mock testing in Terraform projects is a powerful tool for ensuring the quality and correctness of your infrastructure code without the need to create actual resources or require real credentials. Test mocking, available in Terraform v1.7.0 and later, enables the creation of dummy versions of providers, resources, and data sources for testing purposes.
By using mock providers, you can simulate the behavior of actual cloud providers, allowing you to test your configurations thoroughly. These mocked resources can be defined in your test files, and they generate fake data for computed attributes. By leveraging test mocking, you can streamline your testing process and catch potential issues early on in your development cycle.
Overrides for Testing in Terraform
Overrides in Terraform are a valuable feature for modifying existing configurations for testing purposes. Overrides enable developers to alter resource attributes, data source attributes, or even provider settings without changing the actual infrastructure.
By using override blocks with the target attribute, you can specify what resources, data sources, or modules you want to modify for your tests. Overrides are particularly useful for testing configurations with complex structures, ensuring that your code behaves as expected even when actual resources are not being manipulated.
Linting Tools for Terraform Projects
Linting tools play a crucial role in maintaining code quality and consistency in Terraform projects. By using tools like Terraform fmt, TFLint, Checkov, and Terrascan, you can identify syntax errors, enforce style guidelines, and detect potential issues before applying any changes to your infrastructure.
Terraform fmt is particularly useful for formatting Terraform code based on standard rules, while TFLint checks for syntax errors, best practices, and code style consistency. Checkov focuses on security and compliance issues in Terraform code, offering suggestions for fixing vulnerabilities. Terrascan performs static code analysis to identify security vulnerabilities and compliance violations. By incorporating linting tools into your development workflow, you can improve code quality, enhance collaboration, and automate code review processes.
Compliance Testing with Terraform-Compliance
Terraform-compliance is a powerful tool for ensuring compliance with specific conditions in your Terraform code. By writing conditions in YAML files and testing your code against them, you can verify that your infrastructure configurations comply with your defined rules.
For instance, you can specify conditions such as ensuring that an Azure Storage Account is not publicly accessible. By running terraform-compliance with the appropriate policy files, you can validate your code against these conditions and prevent non-compliant configurations from being deployed.
Drift Testing in Terraform
Drift testing in Terraform is essential for detecting differences between your code and the real infrastructure. When running `terraform plan`, Terraform compares the current state of your infrastructure to the state saved in the state file, highlighting any divergences.
You can use driftctl, a free open-source tool, to report on infrastructure drift and identify resources that are not managed by Terraform or are missing on the cloud provider. By performing drift testing, you can ensure that your infrastructure remains in sync with your configuration and address any discrepancies promptly.
Get Control of Your Releases With Zeet's CI/CD & Deployment Platform for Kubernetes and Terraform
Zeet helps you to get more from your cloud, Kubernetes, and Terraform investments and helps your engineering team become strong individual contributors through our CI/CD & deployment platform.
Contact Zeet to learn more about how Zeet help you get seamless cloud deployments every time, and helps your team to become a top-performing engineering team.
Related Reading
- Scalr Vs Terraform
- Atlantis Terraform
- Atlantis Alternatives
- Spacelift Vs Terraform Cloud
- Env0 Vs Terraform Cloud
- Terraform Cloud Alternatives
- Terraform Tools
- Terraform Vs Ansible
- Ansible Vs Terraform
- Terraform Testing Tools