Your infrastructure is code (Chapter 9), and like all code, it can have errors. In this chapter, you’ll learn how to test your infrastructure to detect problems before they reach production. We start with the most basic and cheapest checks: fmt and validate, run automatically in CI. They are the first line of defense for quality.

Why test infrastructure

An error in your Terraform code can cause anything from a silly failure (a misplaced bracket) to a serious disaster (a Security Group leaving your database open to the internet). Just as you test application code before releasing it, you must test your infrastructure. The good news is that there are several levels of testing, from the simplest to the most comprehensive:

Testing levels (from simplest to most complete):
  1. fmt        → consistent formatting         (this subchapter)
  2. validate   → correct syntax                (this subchapter)
  3. security   → Checkov, tfsec                (subchap. 21.2)
  4. integration→ Terratest                     (subchap. 21.3)

We start with the first two, which are the easiest and the ones you should always have.

What is CI (Continuous Integration)

Before we continue, a key concept: CI (Continuous Integration). It’s an automatic system that, every time someone proposes a code change (a Pull Request, subchapter 12.5), runs a series of checks automatically. If any fail, it notifies and blocks the change until it’s fixed.

Someone opens a Pull Request
        │
        ▼
   CI automatically runs:  fmt? validate? security? tests?
        │
        ├─ all OK  → the change can be merged ✓
        └─ something fails → blocked until fixed ✗

Analogy: CI is like an automatic quality control in a factory. Each product (code change) goes down a conveyor belt where machines inspect it. If something doesn’t meet standards, it’s set aside before reaching the market. No one has to manually review each piece: the system does it alone, tirelessly and without forgetting.

We’ll see CI in depth in Chapter 22; for now, just remember it’s where these tests are run automatically.

terraform fmt: consistent formatting

Remember fmt from subchapter 11.4: it formats Terraform code with a uniform style (indentation, alignment). In CI it’s used in check mode, to verify that the code is well formatted, without changing it:

terraform fmt -check
   → if the code is well formatted → passes ✓
   → if NOT → fails, warning that "fmt" needs to be run

Why check formatting in CI? So that all the team’s code has the same style, always. Without this, everyone would format their own way and the code would be a mess of mixed styles. With CI checking, no one can merge poorly formatted code: it’s an automatic standard that eliminates style debates.

terraform validate: correct syntax and logic

Remember validate from subchapter 11.4: it checks that the code is valid (no syntax errors or broken references), without connecting to AWS or creating anything. In CI it’s run like this:

terraform validate
   → if the code is valid → passes ✓
   → if there’s an error (misspelled argument, nonexistent reference) → fails ✗

Why validate in CI? To catch basic errors instantly, before anyone tries to apply the code. If someone misspells an argument or references a resource that doesn’t exist, validate catches it in seconds, and CI blocks the change. It’s much better to discover it here than when you try to deploy.

The typical CI flow

Combining both, a basic CI pipeline for Terraform starts like this:

Pull Request opened
   │
   ├─ 1. terraform fmt -check    → consistent formatting?
   ├─ 2. terraform validate      → valid code?
   ├─ 3. (security analysis)     → subchap. 21.2
   └─ 4. terraform plan          → what would change? (reviewed, subchap. 12.5)

If fmt or validate fail, the process stops there: there’s no point continuing with poorly formatted or invalid code. Only if these basic checks pass do you continue with the others.

Why start here

fmt and validate are the foundation of infrastructure testing for two reasons:

  • They’re extremely cheap: they run in seconds, don’t need AWS credentials, and don’t create anything. There’s no reason not to have them.
  • They catch the most common errors: many day-to-day failures are formatting or syntax errors, and these two commands eliminate them at the root.

Practical tip: even if you don’t have a complete CI pipeline yet, set up at least fmt -check and validate from day one. It’s the minimum effort for the greatest quality return. You can add more advanced tests (security, integration) later.

What you should remember

  • Infrastructure is code, and as such can have errors; you must test it before it reaches production, in levels from least to most complete: fmt → validate → security → integration.
  • CI (Continuous Integration) is an automatic system that runs checks every time a change is proposed (a PR) and blocks those that fail. Like an automatic quality control in a factory.
  • terraform fmt -check verifies that the code has consistent formatting, ensuring a uniform style across the team.
  • terraform validate checks that the code is valid (syntax and references), catching basic errors instantly, without touching AWS.
  • They are the foundation of testing: extremely cheap (seconds, no credentials) and catch the most common errors. Set them up from day one.

In the next subchapter we’ll move up a level: static security analysis with Checkov and tfsec, which detect dangerous configurations before deploying them.

Cloud, AWS & Terraform — From Zero to Expert

Chapter 1 · What is cloud computing

Chapter 2 · The cloud market and major providers

Chapter 3 · Regions, availability zones and edge

Chapter 4 · Compute: EC2

Chapter 5 · Storage: S3

Chapter 6 · Networking: VPC

Chapter 7 · Identity and access: IAM

Chapter 8 · Managed databases

Chapter 9 · Why Infrastructure as Code

Chapter 10 · HCL: the Terraform language

Chapter 11 · Providers and state

Chapter 12 · Your first real infrastructure in Terraform

Chapter 13 · Load balancing and auto scaling

Chapter 14 · Serverless with Lambda

Chapter 15 · Messaging and events

Chapter 16 · Content delivery and DNS

Chapter 17 · Containers on AWS

Chapter 18 · Modules: reuse and composition

Chapter 19 · Workspaces and environment management

Chapter 20 · Remote backends and locking

Chapter 21 · Infrastructure testing

Chapter 22 · Terraform in CI/CD

Chapter 23 · Defense in depth

Chapter 24 · Observability: logs, metrics and traces

Chapter 25 · Cost optimization

Chapter 26 · High availability and disaster recovery

Chapter 27 · AWS Well-Architected Framework

Chapter 28 · Serverless architectures at scale

Chapter 29 · Data platforms on AWS

Chapter 30 · Multi-account and landing zones

Chapter 31 · Platform Engineering and Internal Developer Platform

Chapter 32 · Relevant AWS certifications

Chapter 33 · Projects to consolidate what you've learned

Chapter 34 · Resources and community

© Copyright 2024. All rights reserved