<p>In addition to all the other options mentioned, I would like to mention that InSpec 2.0 added support for cloud provider APIs. Basically, you can continue writing the IaC with Terraform, then write compliancy checks with InSpec for your cloud resources. In addition, InSpec supports writing tests for individual machines if you ever need it.</p>

<p>Here is an article from Christoph Hartmann (co-creator of Inspec) on how to use Inspec with Terraform: <a href="https://lollyrock.com/articles/inspec-terraform/" rel="noreferrer">https://lollyrock.com/articles/inspec-terraform/</a></p>

CC BY-SA 4.0
2018-07-08T17:12:42.873Z
2018-07-08T17:12:42.873Z
Yekta Leblebici
<p>On Aws-Side there is <a href="https://github.com/k1LoW/awspec" rel="noreferrer">https://github.com/k1LoW/awspec</a> - it should be possible, to feed in terraform.state and test, wheter terraform applied correct.</p>

<p>But I think, beyond testing on low level the tool, you used, it's probably a better idea, to think about how to test whole infrastructures. </p>

<p>We're discussing around this idea here:</p>

<p><a href="https://github.com/DomainDrivenArchitecture/dda-cloudspec/blob/development/README.md" rel="noreferrer">https://github.com/DomainDrivenArchitecture/dda-cloudspec/blob/development/README.md</a></p>

<p>For testing invariants upfront, I do not know a ready to use solution ...</p>

<p>We did some experiments using a mix of <code>terraform plan -out=plan.dump</code> and <code>grep</code> for the absence of element names. There is a discussion about a more accessible plan format here: github.com/hashicorp/terraform/issues/11883</p>

<p>But at the moment we're using a manual plan review process for important parts of our infrastructure.</p>

CC BY-SA 3.0
2017-08-24T12:41:11.313Z
The goal is to test the changes in the terraform configuration won't break expected needs, once deployed it's too late, at best you have a fail seeing a DB has been removed where it should not, but you did already break the target environment... the question is about testing the terraform code, not testing the end result, unit tests vs integration tests.
Tensibai
CC BY-SA 3.0
2017-08-24T15:08:31.197Z
good point ... added a section for testing invariants.
jerger
CC BY-SA 3.0
2017-08-24T12:33:00.023Z
2017-08-24T15:07:53.330Z
2017-08-24T15:07:53.330Z
jerger
<p>We recently open sourced <a href="https://blog.gruntwork.io/open-sourcing-terratest-a-swiss-army-knife-for-testing-infrastructure-code-5d883336fcd5" rel="noreferrer">Terratest</a>, our swiss army knife for testing infrastructure code. </p>

<p>Today, you're probably testing all your infrastructure code manually by deploying, validating, and undeploying. Terratest helps you automate this process:</p>

<ol>
<li>Write tests in Go.</li>
<li>Use helpers in Terratest to execute your real IaC tools (e.g., Terraform, Packer, etc.) to deploy real infrastructure (e.g., servers) in a real environment (e.g., AWS).</li>
<li>Use helpers in Terratest to validate that the infrastructure works correctly in that environment by making HTTP requests, API calls, SSH connections, etc.</li>
<li>Use helpers in Terratest to undeploy everything at the end of the test.</li>
</ol>

<p>Here's an example test for some Terraform code:</p>

<pre class="lang-golang prettyprint-override"><code>terraformOptions := &amp;terraform.Options {
  // The path to where your Terraform code is located
  TerraformDir: "../examples/terraform-basic-example",
}

// This will run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)

// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)

// Run `terraform output` to get the value of an output variable
instanceUrl := terraform.Output(t, terraformOptions, "instance_url")

// Verify that we get back a 200 OK with the expected text
// It can take a minute or so for the Instance to boot up, so retry a few times
expected := "Hello, World"
maxRetries := 15
timeBetweenRetries := 5 * time.Second
http_helper.HttpGetWithRetry(t, instanceUrl, 200, expected, maxRetries, timeBetweenRetries)
</code></pre>

<p>These are integration tests, and depending on what you're testing, can take 5 - 50 minutes. It's not fast (though using <a href="https://github.com/gruntwork-io/terratest#iterating-locally-using-docker" rel="noreferrer">Docker</a> and <a href="https://github.com/gruntwork-io/terratest#iterating-locally-using-test-stages" rel="noreferrer">test stages</a>, you can speed <em>some</em> things up), and you'll have to work to make the tests reliable, but it is well worth the time.</p>

<p>Check out the <a href="https://github.com/gruntwork-io/terratest#iterating-locally-using-test-stages" rel="noreferrer">Terratest repo</a> for docs and lots of examples of various types of infrastructure code and the corresponding tests for them.</p>

CC BY-SA 4.0
2018-05-24T09:57:16.230Z
I've also written a blog post that walks through testing one of my example projects with Terratest in more detail: https://brightfame.co/blog/testing-your-terraform-project-with-terratest/. It may be of value to anyone. Cheers, Rob!
Rob Morgan
CC BY-SA 4.0
2019-08-05T07:40:32.977Z
Big fan of Terratest!
jlucktay
CC BY-SA 4.0
2018-05-03T11:31:54.773Z
2019-11-09T22:06:31.587Z
2019-11-09T22:06:31.587Z
Yevgeniy Brikman
<p>As an update to this question, there is now <a href="https://github.com/newcontext-oss/kitchen-terraform" rel="noreferrer">Kitchen-Terraform</a> which allows the testing of Terraform Configuration files without breaking production environments. The repository also includes a few examples for different Terraform providers. </p>

CC BY-SA 3.0
2017-11-17T16:25:44.730Z
2018-01-17T15:27:20.330Z
2018-01-17T15:27:20.330Z
Preston Martin
<p>I saw this elegant, low tech method to test Terraform suggested by <a href="https://github.com/apparentlymart" rel="nofollow noreferrer">apparentlymart</a> in a GitHub issue thread. It's not a appropriate for every situation but it's great for verifying module logic.</p>

<p>Create a root module that includes the module under test and verifies the under-test outputs. Here is a simple example using two files:</p>

<ul>
<li><code>main.tf</code> that will run the tests</li>
<li><code>simple_module/outputs.tf</code> that represents a module under test</li>
</ul>

<h2>./main.tf</h2>

<pre><code>terraform {
  required_version = "&gt;= 0.12"
}

module "simple_module" {
  source = "./simple_module"
}

locals {
  expected = 1
  got      = module.simple_module.module-returns-1
}

# Test Output
output "expect-1" {
  value = upper(local.expected == local.got)
}

output "expect-other" {
  value = "other" == local.got ? upper(true) : "FALSE. Got ${local.got}"
}
</code></pre>

<h2>./simple_module/outputs.tf</h2>

<pre><code>output "module-returns-1" {
  value = 1
}
</code></pre>

<h2>Run the tests</h2>

<pre><code>terraform init
terraform apply -auto-approve
</code></pre>

<pre><code>Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

expect-1 = TRUE
expect-other = FALSE. Got 1
</code></pre>

CC BY-SA 4.0
2019-10-08T15:59:11.523Z
2019-10-08T15:59:11.523Z
mmell
<p>There is currently no full solution to this integrated into Terraform, but there are some building blocks that could be useful to assist in writing tests in a separate programming language.</p>

<p>Terraform produces state files in JSON format that can, in principle, be used by external programs to extract certain data about what Terraform created. While this format is not yet considered officially stable, in practice it changes infrequently enough that people have successfully integrated with it, accepting that they might need to make adjustments as they upgrade Terraform.</p>

<p>What strategy is appropriate here will depend a lot on what exactly you want to test. For example:</p>

<ul>
<li><p>In an environment that's spinning up virtual servers, tools like <a href="http://serverspec.org/" rel="noreferrer">Serverspec</a> can be used to run tests from the perspective of these servers. This can either be run separately from Terraform using some out-of-band process, or as part of the Terraform apply using the <a href="https://www.terraform.io/docs/provisioners/remote-exec.html" rel="noreferrer"><code>remote-exec</code> provisioner</a>. This allows verification of questions like "can the server reach the database?", but is not suitable for questions such as "is the instance's security group restrictive enough?", since robustly checking that requires accessing data from outside of the instance itself.</p></li>
<li><p>It's possible to write tests using an existing test framework (such as RSpec for Ruby, <code>unittest</code> for Python, etc) which gather relevant resource ids or addresses from the Terraform state file and then use the relevant platform's SDK to retrieve data about the resources and assert that they are set up as expected. This is a more general form of the previous idea, running the tests from the perspective of a host <em>outside</em> of the infrastructure under test, and can thus collect a broader set of data to make assertions on.</p></li>
<li><p>For more modest needs, one can choose to trust that the Terraform state is an accurate representation of reality (a valid assumption in many cases) and simply assert directly on that. This is most appropriate for simple "lint-like" cases, such as verifying that the correct resource tagging scheme is being followed for cost-allocation purposes.</p></li>
</ul>

<p>There is some more discussion about this in <a href="https://github.com/hashicorp/terraform/issues/5059" rel="noreferrer">a relevant Terraform Github issue</a>.</p>

<p>In the latest versions of Terraform it is strongly recommended to use a remote backend for any non-toy application, but that means that the state data is not directly available on local disk. However, a snapshot of it can be retrieved from the remote backend using the <code>terraform state pull</code> command, which prints the JSON-formatted state data to stdout so it can be captured and parsed by a calling program.</p>

CC BY-SA 3.0
2017-04-21T18:07:51.280Z
2017-04-21T18:07:51.280Z
Martin Atkins
<p>If you had a <a href="https://www.terraform.io/" rel="noreferrer">Terraform</a> configuration that had a moderate degree of complexity, how would you write tests around the configuration that could be executed as part of a Continuous Integration / Continuous Delivery pipeline?</p>

<p>As an example, you may have a multi-cloud configuration that specifies the following desired state:</p>

<ul>
<li>Azure Container Services to host Docker in Azure</li>
<li>Azure Blob Storage</li>
<li>SQL Azure</li>
<li>EC2 Container Service to host Docker in AWS</li>
<li>Amazon S3 Storage Service</li>
<li>Amazon RDS SQL Server database</li>
</ul>

<p>Potentially <code>terraform apply</code> could create the above from scratch, or transition from a partially deployed state to the above desired state.</p>

<p>I am aware that Terraform splits its work into the <strong>execution plan</strong> stage and the <strong>application</strong> phase which actually makes changes to the target architecture.  Can this be used to write tests against the execution plan, if so are there frameworks to help write these?</p>

CC BY-SA 3.0
2017-04-12T15:22:59.637Z
Maybe useful: https://github.com/hashicorp/terraform/issues/5059
Tensibai
CC BY-SA 3.0
2017-04-12T15:58:10.697Z
Interesting indeed, possibly answer worthy.
Richard Slater
CC BY-SA 3.0
2017-04-13T09:02:34.923Z
I'm not using terraform myself, so I let someone with real experience write an answer :)
Tensibai
<testing><terraform>
How to test a Terraform Configuration?
Richard Slater
# How to test a Terraform Configuration?

(Asked by: username_0 on 2017-04-12)

If you had a [Terraform](https://www.terraform.io/) configuration that had a moderate degree of complexity, how would you write tests around the configuration that could be executed as part of a Continuous Integration / Continuous Delivery pipeline?

As an example, you may have a multi-cloud configuration that specifies the following desired state:

* Azure Container Services to host Docker in Azure
* Azure Blob Storage
* SQL Azure
* EC2 Container Service to host Docker in AWS
* Amazon S3 Storage Service
* Amazon RDS SQL Server database

Potentially `terraform apply` could create the above from scratch, or transition from a partially deployed state to the above desired state.

I am aware that Terraform splits its work into the **execution plan** stage and the **application** phase which actually makes changes to the target architecture. Can this be used to write tests against the execution plan, if so are there frameworks to help write these?

**Tags:** testing, terraform

> **Comments:**
> **username_1**: Maybe useful: https://github.com/hashicorp/terraform/issues/5059  
> **username_0**: Interesting indeed, possibly answer worthy.  
> **username_1**: I'm not using terraform myself, so I let someone with real experience write an answer :)  

---

## 6 answers

### Answer by username_9 on 2017-04-21. Score: 24 | Accepted answer

There is currently no full solution to this integrated into Terraform, but there are some building blocks that could be useful to assist in writing tests in a separate programming language.

Terraform produces state files in JSON format that can, in principle, be used by external programs to extract certain data about what Terraform created. While this format is not yet considered officially stable, in practice it changes infrequently enough that people have successfully integrated with it, accepting that they might need to make adjustments as they upgrade Terraform.

What strategy is appropriate here will depend a lot on what exactly you want to test. For example:

* In an environment that's spinning up virtual servers, tools like [Serverspec](http://serverspec.org/) can be used to run tests from the perspective of these servers. This can either be run separately from Terraform using some out-of-band process, or as part of the Terraform apply using the [`remote-exec` provisioner](https://www.terraform.io/docs/provisioners/remote-exec.html). This allows verification of questions like "can the server reach the database?", but is not suitable for questions such as "is the instance's security group restrictive enough?", since robustly checking that requires accessing data from outside of the instance itself.
* It's possible to write tests using an existing test framework (such as RSpec for Ruby, `unittest` for Python, etc) which gather relevant resource ids or addresses from the Terraform state file and then use the relevant platform's SDK to retrieve data about the resources and assert that they are set up as expected. This is a more general form of the previous idea, running the tests from the perspective of a host *outside* of the infrastructure under test, and can thus collect a broader set of data to make assertions on.
* For more modest needs, one can choose to trust that the Terraform state is an accurate representation of reality (a valid assumption in many cases) and simply assert directly on that. This is most appropriate for simple "lint-like" cases, such as verifying that the correct resource tagging scheme is being followed for cost-allocation purposes.

There is some more discussion about this in [a relevant Terraform Github issue](https://github.com/hashicorp/terraform/issues/5059).

In the latest versions of Terraform it is strongly recommended to use a remote backend for any non-toy application, but that means that the state data is not directly available on local disk. However, a snapshot of it can be retrieved from the remote backend using the `terraform state pull` command, which prints the JSON-formatted state data to stdout so it can be captured and parsed by a calling program.


---

### Answer by username_4 on 2018-05-03. Score: 17

We recently open sourced Terratest, our swiss army knife for testing infrastructure code. 
Today, you're probably testing all your infrastructure code manually by deploying, validating, and undeploying. Terratest helps you automate this process:

Write tests in Go.
Use helpers in Terratest to execute your real IaC tools (e.g., Terraform, Packer, etc.) to deploy real infrastructure (e.g., servers) in a real environment (e.g., AWS).
Use helpers in Terratest to validate that the infrastructure works correctly in that environment by making HTTP requests, API calls, SSH connections, etc.
Use helpers in Terratest to undeploy everything at the end of the test.

Here's an example test for some Terraform code:
terraformOptions := &terraform.Options {
  // The path to where your Terraform code is located
  TerraformDir: "../examples/terraform-basic-example",
}

// This will run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)

// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)

// Run `terraform output` to get the value of an output variable
instanceUrl := terraform.Output(t, terraformOptions, "instance_url")

// Verify that we get back a 200 OK with the expected text
// It can take a minute or so for the Instance to boot up, so retry a few times
expected := "Hello, World"
maxRetries := 15
timeBetweenRetries := 5 * time.Second
http_helper.HttpGetWithRetry(t, instanceUrl, 200, expected, maxRetries, timeBetweenRetries)

These are integration tests, and depending on what you're testing, can take 5 - 50 minutes. It's not fast (though using Docker and test stages, you can speed some things up), and you'll have to work to make the tests reliable, but it is well worth the time.
Check out the Terratest repo for docs and lots of examples of various types of infrastructure code and the corresponding tests for them.

> **Comments:**
> **username_5**: I've also written a blog post that walks through testing one of my example projects with Terratest in more detail: https://brightfame.co/blog/testing-your-terraform-project-with-terratest/. It may be of value to anyone. Cheers, Rob!  
> **username_6**: Big fan of Terratest!  

---

### Answer by username_7 on 2017-11-17. Score: 13

As an update to this question, there is now [Kitchen-Terraform](https://github.com/newcontext-oss/kitchen-terraform) which allows the testing of Terraform Configuration files without breaking production environments. The repository also includes a few examples for different Terraform providers.


---

### Answer by username_2 on 2018-07-08. Score: 7

In addition to all the other options mentioned, I would like to mention that InSpec 2.0 added support for cloud provider APIs. Basically, you can continue writing the IaC with Terraform, then write compliancy checks with InSpec for your cloud resources. In addition, InSpec supports writing tests for individual machines if you ever need it.

Here is an article from Christoph Hartmann (co-creator of Inspec) on how to use Inspec with Terraform: <https://lollyrock.com/articles/inspec-terraform/>


---

### Answer by username_3 on 2017-08-24. Score: 5

On Aws-Side there is <https://github.com/k1LoW/awspec> - it should be possible, to feed in terraform.state and test, wheter terraform applied correct.

But I think, beyond testing on low level the tool, you used, it's probably a better idea, to think about how to test whole infrastructures.

We're discussing around this idea here:

<https://github.com/DomainDrivenArchitecture/dda-cloudspec/blob/development/README.md>

For testing invariants upfront, I do not know a ready to use solution ...

We did some experiments using a mix of `terraform plan -out=plan.dump` and `grep` for the absence of element names. There is a discussion about a more accessible plan format here: github.com/hashicorp/terraform/issues/11883

But at the moment we're using a manual plan review process for important parts of our infrastructure.

> **Comments:**
> **username_1**: The goal is to test the changes in the terraform configuration won't break expected needs, once deployed it's too late, at best you have a fail seeing a DB has been removed where it should not, but you did already break the target environment... the question is about testing the terraform code, not testing the end result, unit tests vs integration tests.  
> **username_3**: good point ... added a section for testing invariants.  

---

### Answer by username_8 on 2019-10-08. Score: 0

I saw this elegant, low tech method to test Terraform suggested by apparentlymart in a GitHub issue thread. It's not a appropriate for every situation but it's great for verifying module logic.
Create a root module that includes the module under test and verifies the under-test outputs. Here is a simple example using two files:

main.tf that will run the tests
simple_module/outputs.tf that represents a module under test

./main.tf
terraform {
  required_version = ">= 0.12"
}

module "simple_module" {
  source = "./simple_module"
}

locals {
  expected = 1
  got      = module.simple_module.module-returns-1
}

# Test Output
output "expect-1" {
  value = upper(local.expected == local.got)
}

output "expect-other" {
  value = "other" == local.got ? upper(true) : "FALSE. Got ${local.got}"
}

./simple_module/outputs.tf
output "module-returns-1" {
  value = 1
}

Run the tests
terraform init
terraform apply -auto-approve

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

expect-1 = TRUE
expect-other = FALSE. Got 1


---

