Terraform 1.7 adds test mocking and config-driven remove
Now generally available, HashiCorp Terraform 1.7 adds mocking capabilities to the Terraform test framework and a config-driven state removal workflow.
We’re excited to announce that HashiCorp Terraform 1.7 is now generally available, ready for download, and available for use in Terraform Cloud. Terraform 1.7 features a new mocking capability for the Terraform test framework, a new method for removing resources from state, and an enhancement for config-driven import. These additions help Terraform developers more thoroughly test their modules and gives operators safer and more efficient options for state manipulation.
» Terraform test mocking
In Terraform 1.6 we introduced the Terraform testing framework, a native option to perform unit and integration testing of your Terraform code using the HashiCorp Configuration Language (HCL). Terraform 1.7 brings several improvements to the testing framework, highlighted by the new mocking feature.
Previously, all tests were executed by making actual provider calls using either a plan or apply operation. This is a great way to observe the real behavior of a module. But it can also be useful to mock provider calls to model more advanced situations and to test without having to create actual infrastructure or requiring credentials. This can be especially useful with cloud resources that take a long time to provision, such as databases and higher-level platform services. Mocking can significantly reduce the time required to run a test suite with many different permutations, giving module authors the ability to thoroughly test their code without slowing down the development process.
Test mocking adds powerful flexibility to module testing through two primary functions: mock providers and overrides.
» Mock providers
A mocked provider or resource in a Terraform test will generate fake data for all computed attributes that would normally be provided by the underlying provider APIs. By employing aliases, mocked and real providers can be used together to create a flexible Terraform test suite for your modules.
The new mock_provider
block defines a mock provider, and within this block you can specify values for computed attributes of resources and data sources. This example mocks the AWS provider and sets a specific value for the Amazon S3 bucket resource. Test runs using the mocked version of this provider will return the specified arn
value for all S3 bucket resources instead of randomly generated fake data:
example.tftest.hcl
mock_provider "aws" {
mock_resource "aws_s3_bucket" {
defaults = {
arn = "arn:aws:s3:::test-bucket-name"
}
}
}
run "sets_bucket_name" {
variables {
bucket_name = "test-bucket-name"
}
# Validates a known attribute set in the resource configuration
assert {
condition = output.bucket == "test-bucket-name"
error_message = "Wrong ARN value"
}
# Validates a computed attribute using the mocked resource
assert {
condition = output.arn == "arn:aws:s3:::test-bucket-name"
error_message = "Wrong ARN value"
}
}
» Overrides
In addition to mocking whole providers, you can also override specific instances of resources, data sources, and modules. Override blocks can be placed at the root of a Terraform test file to apply to all test runs, or within an individual run
block, and can be used with both real and mocked providers. Common use cases for overrides include cutting down test execution time for resources that take a long time to provision, child modules where you’re concerned only with simulating the outputs, or to diversify the attributes of a data source for various test scenarios. This example overrides a module and mocks the output values:
example.tftest.hcl
mock_provider "aws" {}
override_module {
target = module.big_database
outputs = {
endpoint = "big_database.012345678901.us-east-1.rds.amazonaws.com:3306"
db_name = "test_db"
username = "fakeuser"
password = "fakepassword"
}
}
run "test" {
assert {
condition = module.big_database.username == "fakeuser"
error_message = "Incorrect username"
}
}
» Learn more about test mocking
There’s much more you can do with the new mocking capabilities of the Terraform test framework to help enhance your testing and produce higher-quality modules. To learn more, check out the Mocks documentation, and try it out by following the updated Write Terraform tests tutorial.
Along with test mocking, Terraform 1.7 includes several other enhancements to the test framework. You can now:
- Reference variables and run outputs in test provider blocks
- Use HCL functions in variable and provider blocks
- Load variable values for tests from
*.tfvars
files.
For a deep dive on all things testing, check out the recently updated Testing HashiCorp Terraform blog post.
» Config-driven remove
During the infrastructure lifecycle, it’s sometimes necessary to modify the state of a resource. The Terraform CLI has multiple commands related to state manipulation, but these all face similar challenges: they operate on only one resource at a time, must be performed locally with direct access to state and credentials, and they immediately modify the state. This is risky because it leaves the configuration and state out of sync, which can lead to accidental resource changes. That’s why in Terraform 1.1 we introduced the concept of config-driven refactoring with the moved
block, and continued this with config-driven import in Terraform 1.5. Today with Terraform 1.7, this concept has again been extended with config-driven remove.
There are several reasons why you might need to remove a resource from state without actually destroying it:
- Moving resources between workspaces
- Cleaning up state after apply-time failures
- Refresh failures due to manual resource changes
- Provider deprecations and upgrades
As an alternative to the terraform state rm
command, the removed
block addresses all of these challenges. Just like the moved
and import
blocks, state removal can now be performed in bulk and is plannable, so you can be confident that the operation will have the intended effect before modifying state. Removed blocks have a simple syntax:
removed {
# The resource address to remove from state
from = aws_instance.example
# The lifecycle block instructs Terraform not to destroy the underlying resource
lifecycle {
destroy = false
}
}
Config-driven remove is also compatible with all Terraform Cloud workflows including VCS-driven workspaces. And soon, structured run output in Terraform Cloud will be able to visually render removal actions alongside other plan activity. Read more about using removed
blocks with resources and using removed
blocks with modules in the Terraform documentation, and try it out with the updated Manage resources in Terraform state tutorial.
» Import block for_each
Terraform 1.7 also includes an enhancement for config-driven import: the ability to expand import
blocks using for_each
loops. Previously you could target a particular instance of a resource in the to
attribute of an import block, but you had to write a separate import block for each instance. Now you can accomplish this with a single import block:
locals {
buckets = {
"staging" = "bucket-demoapp-staging"
"uat" = "bucket-demoapp-uat"
"prod" = "bucket-demoapp-prod"
}
}
import {
for_each = local.buckets
to = aws_s3_bucket.example[each.key]
id = each.value
}
resource "aws_s3_bucket" "example" {
for_each = local.buckets
bucket = each.value
}
This technique can also be used to expand imports across multiple module instances. Learn more and see an example in the Import documentation.
» Get started with Terraform 1.7
For more details and to learn about all of the enhancements in Terraform 1.7, please review the full HashiCorp Terraform 1.7 changelog. Additional resource links include:
- Download Terraform 1.7
- Sign up for a free Terraform Cloud account
- Read the Terraform 1.7 upgrade guide
- Get hands-on with tutorials at HashiCorp Developer
As always, this release wouldn't have been possible without all of the great community feedback we've received via GitHub issues and from our customers. Thank you!
Sign up for the latest HashiCorp news
More blog posts like this one
Terraform delivers launch-day support for Amazon S3 Tables, EKS Hybrid Nodes, and more at re:Invent
The Terraform provider for AWS now enables users to manage a variety of new services just announced at re:Invent.
HashiCorp at re:Invent 2024: Infrastructure Lifecycle Management with AWS
A recap of HashiCorp infrastructure news and developments on AWS from the past year, from a new provider launch to simplifying infrastructure provisioning and more.
Simplify policy adoption in Terraform with pre-written Sentinel policies for AWS
HashiCorp introduces a new pre-written policy library co-developed with AWS, aiming to reduce the barrier of adoption for policy as code infrastructure workflows.