Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Terraform By James Joyner IV · · 9 min read

How to Use mock_provider in Terraform Tests (.tftest.hcl)

Quick answer

Use mock_provider in Terraform tests (.tftest.hcl) to fake AWS providers, run terraform test with command = plan, and avoid real API calls. Examples, gotchas, and when to mock.

  • #terraform
  • #testing
  • #mock_provider
  • #troubleshooting
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

What mock_provider Does

Terraform’s native test framework (stable since Terraform 1.6, with mocking added in 1.7) lets you write tests in .tftest.hcl files and run them with terraform test. By default a test configures real providers and can make real API calls. A mock_provider block replaces a real provider with a fake one so that terraform test never contacts a cloud API.

When you mock a provider, Terraform generates fake-but-schema-valid values for every attribute that would normally be computed by the provider (IDs, ARNs, timestamps). This means you can run a full plan — and even apply — against mock_provider "aws" {} without credentials and without creating anything. It is the fastest way to unit-test the logic of a module: variable validation, count/for_each expansion, conditional resources, and output wiring.

A Minimal .tftest.hcl Example

Assume a small module that creates an S3 bucket and exposes its ARN as an output. Place the test file next to your configuration (Terraform discovers *.tftest.hcl in the working directory and in tests/).

# main.tftest.hcl
mock_provider "aws" {}

run "bucket_is_planned" {
  command = plan

  variables {
    bucket_name = "example-logs"
  }

  assert {
    condition     = aws_s3_bucket.this.bucket == "example-logs"
    error_message = "Bucket name did not propagate to the resource"
  }
}

Run it:

terraform init
terraform test
main.tftest.hcl... in progress
  run "bucket_is_planned"... pass
main.tftest.hcl... teardown
main.tftest.hcl... pass

Success! 1 passed, 0 failed.

The single mock_provider "aws" {} line is what makes this run offline. Because command = plan, Terraform stops at the plan phase, so even computed attributes that the mock cannot fully predict are fine to assert against known inputs.

Overriding the Fake Values

Auto-generated mock values are random, which is a problem when an output depends on a computed attribute like an ARN and you want to assert its exact value. Use override_resource (or override_data for data sources) to pin specific attributes:

mock_provider "aws" {
  override_resource {
    target = aws_s3_bucket.this
    values = {
      arn = "arn:aws:s3:::example-logs"
    }
  }
}

run "arn_output_is_correct" {
  command = plan

  variables {
    bucket_name = "example-logs"
  }

  assert {
    condition     = output.bucket_arn == "arn:aws:s3:::example-logs"
    error_message = "bucket_arn output did not match the mocked ARN"
  }
}

You can place override_resource, override_data, and override_module either inside the mock_provider block (applies to the whole file) or inside an individual run block (applies only to that run). Run-level overrides win when both are present.

When to Mock vs. Use a Real Provider

Mocking is not always the right call. Use this split:

  • Mock the provider for unit tests: fast feedback, no credentials, testing module logic, running in CI on every push. This is the majority of your tests.
  • Use a real provider for integration tests: command = apply against a real (sandbox) account to confirm the resource actually creates, that IAM permissions are right, and that provider-side validation passes. Keep these fewer and gate them behind credentials.

A common pattern is two files: unit.tftest.hcl with mock_provider, and integration.tftest.hcl with a real provider block plus command = apply. You can generate scaffolding and assertions for both from the DevOps AI prompt library at /prompts/?stack=terraform.

Step-by-Step Resolution

  1. Add a mock_provider "aws" {} block at the top of your .tftest.hcl file (one per provider you need to fake).
  2. Write a run block with command = plan for pure logic checks; use command = apply only when you need computed values resolved through the mock.
  3. Set variables { ... } inside each run to feed inputs, matching your module’s variable names exactly.
  4. Add assert blocks referencing resources (aws_s3_bucket.this.bucket) and outputs (output.bucket_arn).
  5. Pin non-deterministic attributes with override_resource/override_data when an assertion needs an exact ARN, ID, or timestamp.
  6. Run terraform init then terraform test, and read the per-run pass/fail lines to locate a failing assertion.

Gotchas

  • Mocks are not real validation. A mock_provider will happily accept an invalid configuration that a real provider would reject at apply time. Mocking tests your logic, not the provider’s constraints.
  • Random values change per run. Never assert on an un-overridden computed attribute; it will pass once and fail the next time. Override it or assert on inputs.
  • One block per provider. If your module uses aws and random, you need mock_provider "aws" {} and mock_provider "random" {} (or a real one for whichever you want live).
  • command = apply still creates nothing with a mock, but it does resolve the full dependency graph, which surfaces different errors than plan.
  • File discovery. Tests must live in the root working directory or in tests/. A stray .tftest.hcl in a subdirectory will not run.

Frequently Asked Questions

What does mock_provider do in a tftest.hcl file? It replaces a real provider with a fake one that returns schema-valid, auto-generated values, so terraform test can run plans and applies without credentials or real API calls.

Do I need AWS credentials to run terraform test with mock_provider? No. That is the whole point of mocking — the provider never authenticates or contacts the API, so tests run offline in CI without any secrets.

Why do my assertions on ARNs or IDs fail intermittently? Mocked computed attributes are randomly generated each run. Pin them with override_resource (or override_data) so the value is deterministic before you assert on it.

Can I mock some providers and use others for real in the same test? Yes. Add mock_provider for the ones you want faked and a normal provider block for the ones you want live; each provider is independent.

Should I use command = plan or command = apply? Use plan for fast logic checks, and apply only when an assertion needs the mock to resolve computed values through the full graph. For more patterns, see the Terraform guides.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.