Testing IaC: Terratest & InSpec
Prove infrastructure works before prod.
Infrastructure code deserves testing as much as application code — a bad module or a broken change can take down production just as surely as a bug. IaC testing spans a spectrum: static checks (validate, format, lint, and the scanners you already met) catch syntax and known issues cheaply; then plan-based tests assert what a plan would do; and finally integration tests actually create real infrastructure in a sandbox, verify it works, and tear it down. The higher you go, the more confidence and the more cost — so you use each level for what it is good at.
Terratest: real infrastructure, verified
Terratest is the standard for integration-testing IaC: a Go library that programmatically runs terraform apply in a sandbox account, makes assertions against the real resources (the server responds, the bucket has the right policy, the output is correct), and then runs destroy to clean up — even if the test fails. This is the strongest confidence you can get: you proved the module actually builds working infrastructure, not just that it parses. Because it creates real resources, it costs money and time, so you run it for important reusable modules and before releases, not on every tiny change.
func TestNetworkModule(t *testing.T) {opts := &terraform.Options{ TerraformDir: "../modules/network" }defer terraform.Destroy(t, opts) // always tear down, even on failureterraform.InitAndApply(t, opts) // actually build it in a sandboxsubnetID := terraform.Output(t, opts, "private_subnet_id")assert.NotEmpty(t, subnetID) // verify the module produced a real subnet}
InSpec and the pragmatic mix
InSpec is a compliance-and-testing framework that verifies the state of infrastructure against a described spec — "port 22 should not be open to the world," "this service should be running" — readable enough to double as executable compliance documentation. In practice, most teams lean heavily on the cheap layer (fmt, validate, tflint, scanners, policy) which runs on every change, add Terratest for their critical shared modules, and use InSpec-style checks for compliance verification. You do not need every layer everywhere; you need the cheap checks always and real tests where the blast radius justifies the cost.