
September 11, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
You ship Terraform modules, then production breaks because a security group rule never opened port 443. Static validation catches syntax errors, but it cannot prove your stack actually works. That gap is exactly why teams test infrastructure code with Terratest — a Go library that runs real terraform apply cycles and asserts on live cloud resources. If you already treat Terraform modules as reusable products, Terratest gives those modules the same integration-test discipline you expect from application code.
terraform.InitAndApply, assert outputs and HTTP endpoints against real cloud resources, then run terraform.Destroy in cleanup — catching deploy failures that terraform validate alone cannot detect.What is Terratest and why should you test infrastructure code with it?
Terratest is an open-source Go library maintained by Gruntwork. It wraps Terraform, Packer, Docker, Kubernetes, and AWS SDK calls inside standard Go tests. Your test binary becomes the orchestrator: provision, verify, tear down.
That model differs from lint-only checks. terraform plan shows intent. Terratest proves the result. On shared EC2 infrastructure I maintain with GitLab CI and Deployer 7, a bad Terraform change can take down multiple sister sites at once. A Terratest suite that applies a module into an isolated account or sandbox VPC pays for itself after one prevented outage.
Terratest sits near the top of the testing pyramid for infrastructure. Unit tests cover HCL parsing and policy checks. Integration tests provision real resources. Keep both layers; do not replace policy-as-code gates with slow apply tests alone.
Common assertions include:
- Terraform output values match expected strings or CIDR blocks.
- HTTP endpoints return 200 after a load balancer provisions.
- DNS records resolve to the correct IP within a timeout window.
- IAM policies grant only the permissions your module documents.
- S3 buckets enforce encryption and block public access.
The official Terratest documentation at terratest.gruntwork.io remains the primary reference. Pair it with HashiCorp's Terraform docs for provider-specific behaviour that tests must account for.
How do you set up Terratest for Terraform module testing?
You need Go 1.21 or newer, Terraform CLI, cloud credentials, and a module directory. Terratest does not replace Terraform; it executes it as a subprocess from Go tests.
Install prerequisites
On Ubuntu 24.04 — the OS I use on production servers — install Go and Terraform first:
sudo apt update
sudo apt install -y golang-go unzip
wget https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_amd64.zip
unzip terraform_1.9.8_linux_amd64.zip
sudo mv terraform /usr/local/bin/
go version
terraform version Initialize a Go module inside your infrastructure repository:
mkdir -p infra/test && cd infra/test
go mod init github.com/yourorg/infra-tests
go get github.com/gruntwork-io/terratest/modules/terraform@latest
go get github.com/stretchr/testify/require Organize tests to mirror your module tree. A typical layout:
infra/
├── modules/
│ └── vpc/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── test/
├── go.mod
└── vpc_test.go Configure cloud credentials safely
Never hard-code access keys inside test files. Use environment variables or OIDC in CI. For local runs, export a dedicated sandbox profile:
export AWS_PROFILE=terratest-sandbox
export AWS_DEFAULT_REGION=ap-south-1
export TF_VAR_environment=test Restrict the sandbox account with SCPs or IAM boundaries. A forgotten defer terraform.Destroy in a shared production account creates real bills and security exposure. I've seen orphaned RDS instances from manual testing; automated cleanup is non-negotiable.
If you manage servers manually today, moving toward tested modules aligns with professional Linux system administration practices — infrastructure becomes versioned, reviewable, and repeatable.
How do you write your first Terratest integration test?
Start with one small module: an S3 bucket, a security group, or a single-purpose VPC. Large stacks make failures hard to diagnose and runs expensive.
Minimal VPC module test
Create infra/test/vpc_test.go:
package test
import (
"testing"
"time"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/require"
)
func TestVpcModuleCreatesExpectedCidr(t *testing.T) {
t.Parallel()
terraformOptions := &terraform.Options{
TerraformDir: "../modules/vpc",
Vars: map[string]interface{}{
"vpc_cidr": "10.42.0.0/16",
"name": "terratest-vpc",
},
EnvVars: map[string]string{
"AWS_DEFAULT_REGION": "ap-south-1",
},
}
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
vpcCidr := terraform.Output(t, terraformOptions, "vpc_cidr")
require.Equal(t, "10.42.0.0/16", vpcCidr)
} Run it:
cd infra/test
go test -v -timeout 30m ./... The -timeout flag matters. Cloud APIs are slow. A default 10-minute Go timeout kills legitimate applies mid-flight.
Add HTTP and retry assertions
For load-balancer or compute modules, use Terratest's HTTP helper with retries. CloudFront and ALB endpoints often need 30–90 seconds before they respond:
import (
"github.com/gruntwork-io/terratest/modules/http-helper"
)
func TestAlbResponds200(t *testing.T) {
t.Parallel()
/* ... terraform InitAndApply ... */
url := terraform.Output(t, terraformOptions, "alb_url")
http_helper.HttpGetWithRetry(t, url, nil, 200, "body", 30, 5*time.Second)
} Go's testing package supports parallel tests via t.Parallel(). Use it cautiously with Terratest. Parallel applies against one AWS account can hit rate limits or state-lock collisions. Group related tests or use separate state file keys per test via TerraformDir overrides and unique name variables.
Follow idempotent infrastructure principles inside modules themselves. Tests should be able to re-run without manual state surgery. Unique resource names via random_id or test-scoped prefixes prevent collisions when a prior destroy partially failed.
For Packer golden images, Terratest can build an AMI and assert SSH connectivity. That pairs naturally with immutable infrastructure workflows — test the image before Terraform ever references it.
How do you run Terratest in CI/CD pipelines without blowing the budget?
Integration tests cost money and time. A full VPC plus NAT gateway test might run 12–20 minutes and spend Rs 200–400 (~USD 1.50–3.00) per run in AWS ap-south-1. Pipeline design must gate when real applies happen.
Recommended CI stages
- Fast lint stage —
terraform fmt -check,terraform validate, tflint, and OPA/Conftest policy checks. Runs on every push. - Plan-only stage —
terraform planagainst a read-only role. Catches dependency errors without creating resources. - Terratest stage — full apply and destroy. Run on main branch merges, nightly schedules, or when module paths change.
- Post-deploy smoke — optional HTTP checks against staging after zero-downtime Terraform updates.
Example GitLab CI job:
terratest:
stage: integration
image: golang:1.23
services: []
variables:
AWS_DEFAULT_REGION: ap-south-1
before_script:
- apt-get update && apt-get install -y unzip
- curl -fsSL https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_amd64.zip -o tf.zip
- unzip tf.zip && mv terraform /usr/local/bin/
script:
- cd infra/test
- go test -v -timeout 45m ./...
rules:
- if: $CI_COMMIT_BRANCH == "main"
- changes:
- infra/modules/**/*
id_tokens:
AWS_ROLE_ARN:
aud: sts.amazonaws.com Use OIDC federation instead of long-lived CI secrets. Rotate nothing; the pipeline assumes a short-lived role. This mirrors how I configure GitLab CI deploy keys on production — ephemeral credentials reduce blast radius.
Wire Terratest results into the same quality mindset as code coverage gates in CI. A failed infrastructure test should block merge the same way a failing PHPUnit suite would on a Laravel app. Treat infra repos as product code, not ops scratchpads.
Manage test fixtures like application test data. Store minimal tfvars in infra/test/fixtures/ and document assumptions. The same discipline applies to test data management for pipelines — reproducible inputs, no secrets in Git.
For regex-heavy output parsing in custom assertions, a local regex tester saves debugging time before you embed patterns in Go.
Terratest vs other infrastructure testing tools — which should you choose?
No single tool covers every layer. Mature teams combine static analysis, policy checks, and selective integration tests. Terratest excels when you need Go-native control flow, retries, and multi-tool orchestration in one test binary.
| Tool | Language | Provisions real resources | Best for | Trade-off |
|---|---|---|---|---|
| Terratest | Go | Yes | End-to-end module and stack verification | Slow, costs money, needs cloud sandbox |
| terraform test (CLI) | HCL | Optional (mock or real) | Native Terraform 1.6+ unit tests | Less flexible for HTTP retries and custom logic |
| Checkov / tfsec | Python / Go | No | Security misconfiguration scanning | Cannot prove runtime behaviour |
| OPA / Conftest | Rego | No | Policy-as-code on plans | Policy only; no live endpoint checks |
| kitchen-terraform | Ruby | Yes | Chef-era Terraform testing | Smaller community than Terratest in 2026 |
| LocalStack + mocks | Various | Emulated | Fast feedback for AWS-shaped APIs | Emulator gaps; not full cloud fidelity |
My practical recommendation: run Checkov and Conftest on every PR. Add native terraform test blocks for pure HCL logic. Reserve Terratest for modules where a wrong apply breaks production — networking, IAM, load balancers, databases.
That layered approach resembles chaos engineering philosophy applied earlier in the pipeline. You validate assumptions before customers hit a 503.
Teams adopting GitOps for infrastructure still benefit from Terratest before modules enter the GitOps repo. Test the module, then let Argo CD or Flux reconcile known-good artefacts.
On infrastructure-heavy client work such as SRP Infrastructure Development Nepal, proving modules in a sandbox before production rollout reduces rollback incidents. The same mindset applies whether you deploy Laravel on EC2 or Kubernetes with Terraform.
Go's built-in test tooling is documented at go.dev. Terratest extends it; you do not learn a proprietary DSL. If your platform team already writes Go operators or CLI tools, Terratest fits naturally.
Common mistakes to avoid
- Skipping
defer terraform.Destroy— the most expensive bug in infra testing. - Running parallel tests against one state file — state lock errors and flaky CI.
- Testing entire environments instead of isolated modules — 45-minute runs nobody waits for.
- Hard-coding region-specific AMI IDs — tests break when AWS deprecates an image.
- Ignoring cost alerts on the sandbox account — NAT gateways add up fast.
Professional testing and optimization services treat infrastructure repos as first-class software. Terratest is one piece of that broader quality stack alongside application test suites like ParaTest for PHP and deployment automation.
Key Takeaways
- Terratest runs real
terraform applycycles from Go tests and catches failures thatvalidateandplanmiss. - Always call
defer terraform.Destroyand use an isolated sandbox account with OIDC credentials in CI. - Mirror your module tree with one test file per module; keep tests small and timeout-friendly.
- Run Terratest on main merges or module path changes — not on every feature-branch push.
- Combine Terratest with Checkov, Conftest, and native
terraform testfor a complete IaC quality gate. - Treat infrastructure code like product code: reviewed, versioned, and blocked from merge on failure.
People Also Ask
Does Terratest work with Terraform Cloud and remote state?
Yes. Pass backend configuration through terraform.Options or use a generated backend config file in your test fixture directory. Ensure each test uses a unique state key so parallel runs do not corrupt shared state. Many teams create a dedicated Terraform Cloud workspace per module test.
How long should Terratest tests take?
A focused single-resource test often completes in 3–8 minutes. Full stack tests with NAT gateways, RDS, and ALBs can exceed 25 minutes. Set Go's -timeout to at least 30–45 minutes for CI. Split large environments into module-level tests to keep feedback loops tolerable.
Can you test infrastructure code with Terratest without AWS?
Terratest supports GCP, Azure, and Kubernetes modules through the same Go API. You can also test Docker and Packer builds locally without cloud spend. For AWS-shaped fast feedback, some teams use LocalStack — but validate critical paths against real APIs before production.
Is Terratest still maintained in 2026?
Gruntwork actively maintains Terratest on GitHub with regular releases. The ecosystem is mature. For greenfield Terraform 1.6+ projects, evaluate native terraform test alongside Terratest — use HCL tests for pure logic and Terratest when you need HTTP retries, SSH checks, or multi-step orchestration in Go.
Ship infrastructure you can prove works
Manual terraform apply in production is a gamble. When you test infrastructure code with Terratest, you replace that gamble with evidence — live resources that match your module contract before any customer traffic hits them. Start with one module, one sandbox account, and one CI job on main. Expand coverage as modules stabilize.
If you want help designing Terraform modules, CI pipelines, or a full IaC testing strategy for a Nepal or remote team, contact us to discuss your stack. You can also read more from Kokil Thapa on Laravel deployment, Linux administration, and the broader infrastructure-as-code landscape.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

