If you are working with Terraform to manage cloud infrastructure such as AWS, writing unit tests is an important step to ensure your code works as expected without deploying real resources. In this blog, I will guide you through creating unit tests for a simple Terraform source code: provisioning an EC2 instance via a module. We will use the Terraform Test feature (available from Terraform 1.6 onwards) to mock providers and validate outputs.
Project Structure
The source code we are working with follows a basic structure:
- main.tf: The main file that calls the module and sets up the provider.
- modules/ec2_instance/: The module that provisions the EC2 instance.
- tests/unit.tftest.hcl: The test file with mocks and assertions.
1. Set Up Basic Terraform Source Code.
First, create the project folder structure.
1.1 Create main.tf.
This file configures the AWS provider and calls the EC2 module:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
module "web_server" {
source = "./modules/ec2_instance" # Adjust path if needed
env_name = "dev"
instance_type = "t3.micro"
ami_id = "ami-0fa3fe0fa7920f68e" # Replace with a valid AMI ID for your region
}
output "server_ip" {
value = module.web_server.public_ip
}
1.2 Create the ec2_instance Module.
Inside modules/ec2_instance, add the following files:
main.tf
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "web-server-${var.env_name}"
}
}
output "public_ip" {
value = aws_instance.web.public_ip
}
output "instance_type" {
value = aws_instance.web.instance_type
}
output "ami" {
value = aws_instance.web.ami
}
variables.tf
variable "env_name" {
description = "Environment name"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
}
variable "ami_id" {
description = "AMI ID for the EC2 instance"
type = string
}
2. Introduction to Terraform Test.
Terraform Test is an integrated framework for writing tests for Terraform code. It allows you to:
- Mock providers: Simulate providers (like AWS) to avoid creating real resources, saving cost and time.
- Run blocks: Execute commands such as
applyorplanin a test environment. - Assertions: Validate conditions on outputs or resources.
To run tests, you need Terraform >= 1.6. Run terraform test from the project root.
3. Write Unit Tests
Create a tests folder in the project root and add unit.tftest.hcl.
mock_provider "aws" {
alias = "mock"
mock_resource "aws_instance" {
defaults = {
id = "i-1234567890abcdef0"
public_ip = "192.0.2.1"
private_ip = "10.0.0.1"
arn = "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0"
}
}
}
run "test_web_server_instance_type" {
command = apply
providers = {
aws = aws.mock
}
assert {
condition = module.web_server.instance_type == "t3.micro"
error_message = "Instance type does not match expected value."
}
}
run "test_web_server_module_ami" {
command = apply
providers = {
aws = aws.mock
}
assert {
condition = output.server_ip == "192.0.2.1"
error_message = "The public IP output does not match the expected mocked value."
}
}
run "test_web_server_module_ami_ip" {
command = apply
providers = {
aws = aws.mock
}
assert {
condition = output.server_ip == "192.0.2.1"
error_message = "The public IP output does not match the expected mocked value."
}
}
Explanation of the Test File
-
mock_provider: Simulates the AWS provider. We mock theaws_instanceresource with default values (likepublic_ip) so Terraform does not call real AWS APIs. -
runblock: Executesapplywith the mock provider. No variables are needed since they are hardcoded inmain.tf. assert: Validates outputs from the module and root configuration. If the condition fails, the test fails with the given error message.
4. Run Unit Tests
The result after running the command terraform test.
taipham@Tais terraform2 % terraform test
tests/unit.tftest.hcl... in progress
run "test_web_server_intance_type"... pass
run "test_web_server_module_ami"... pass
run "test_web_server_module_ami_ip"... pass
tests/unit.tftest.hcl... tearing down
tests/unit.tftest.hcl... pass
Success! 3 passed, 0 failed.
5. Best Practices for Unit Tests in Terraform
- Isolate tests: Test modules individually if possible (place test files inside the module folder).
- Mock only what’s necessary: Keep mocks simple to avoid complexity.
- Meaningful assertions: Validate inputs, outputs, and tags to ensure correctness.
- Integrate with CI/CD: Run
terraform testin pipelines (e.g., GitHub Actions) for automation. - Advanced usage: Use
expect_failuresfor negative tests or test multiple scenarios with variables.
Conclusion
With unit tests, you can be confident that your Terraform code works correctly before applying it to real infrastructure. In this example, we tested an EC2 instance without incurring AWS costs.
Whether you need scalable software solutions, expert IT outsourcing, or a long-term development partner, ISB Vietnam is here to deliver. Let’s build something great together—reach out to us today. Or click here to explore more ISB Vietnam's case studies.
[References]
https://developer.hashicorp.com/terraform
https://www.sudeepa.com/?p=382 [Image link]


