linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/kb/Testing/tf-test-mocks

kb/testing ── Testing ── intermediate

Mock providers: mock_provider, override_resource, override_data

A mock provider replaces a real AWS provider with synthetic responses. Tests run without the cloud, in seconds rather than minutes. Declare one in `*.tftest.hcl` with `mock_provider "aws"`. To substitute a single resource or data source, use `override_resource` or `override_data`. Without mocks, every `command = apply` block requires LocalStack.

view as markdownaka: terraform-mock-provider, tftest-mocks, terraform-override

Why mocks

terraform test with command = apply calls the provider by default. AWS costs money and adds latency; LocalStack has to be started and waited on. For unit-testing a module that is overkill: you can verify that a bucket name generates the right ARN without a single API call.

A mock provider answers every provider call with synthetic data. Available since Terraform 1.7.

mock_provider for the whole file

hcl
# tests/unit.tftest.hcl
mock_provider "aws" {}
run "naming" {
  command = apply  # apply is fine, mock does not reach the cloud
  variables {
    name = "test-bucket"
  }
  assert {
    condition     = aws_s3_bucket.this.bucket == "test-bucket"
    error_message = "name not propagated"
  }
}

mock_provider "aws" {} with no arguments gives every AWS resource and data source default mock values. Terraform generates placeholders automatically: strings get "unknown", numbers get 0, booleans get false, sets and lists get empty collections.

Apply "runs", but nothing reaches the cloud.

Default values for specific types

If the generated defaults break your logic (for example, a module reads aws_s3_bucket.this.id and builds other names from it), set explicit defaults:

hcl
mock_provider "aws" {
  mock_resource "aws_s3_bucket" {
    defaults = {
      id  = "mocked-bucket-id"
      arn = "arn:aws:s3:::mocked-bucket"
    }
  }
  mock_data "aws_caller_identity" {
    defaults = {
      account_id = "111111111111"
      arn        = "arn:aws:iam::111111111111:user/test"
      user_id    = "AIDA1234567890"
    }
  }
}

Now aws_s3_bucket.this.id will consistently return mocked-bucket-id for every test in that file.

Per-run override

File-level mocks are identical across all run blocks. When one scenario needs a specific value, use override_resource or override_data inside that run:

hcl
run "private_bucket_acl" {
  command = apply
  override_resource {
    target = aws_s3_bucket.this
    values = {
      id  = "specific-private-bucket"
      arn = "arn:aws:s3:::specific-private-bucket"
    }
  }
  assert {
    condition     = aws_s3_bucket_acl.this.bucket == "specific-private-bucket"
    error_message = "ACL refers to wrong bucket"
  }
}

target is the resource address inside the module under test. An override takes precedence over mock_resource ... defaults at the file level.

Override without mock_provider

If most of your tests are real (running against LocalStack) but you want to stub out one data source to avoid an external dependency, skip mock_provider entirely and use only an override:

hcl
run "with_fixed_account" {
  command = plan
  override_data {
    target = data.aws_caller_identity.current
    values = {
      account_id = "999999999999"
    }
  }
  assert {
    condition     = local.bucket_name == "logs-999999999999"
    error_message = "account_id not woven into name"
  }
}

All other resources go to the real provider (or LocalStack, whichever is configured). Only aws_caller_identity is substituted.

Which tests need mocks, which need real providers

What you are testingTest type
Name generation from variablesmock, no cloud needed
Conditional logic (count = var.enabled ? 1 : 0)mock
Value passing between module resourcesmock
That the module actually creates a resource with the right configreal (LocalStack or AWS)
That cross-resource policies (bucket policy) are applied correctlyreal

The rule: if an assertion can be written without attributes that are "known after apply", use a mock. You will save hours in CI.

Mocks do not require init -upgrade

terraform init with a mock provider completes faster because Terraform does not download the real provider binary. It only fetches the schema from the official plugin for type-checking. In CI that saves several minutes.

Default behavior: what a mock returns

When you do not set defaults, the mock provider generates values from the attribute's schema:

Attribute typeMock value
string"foo"
number0
boolfalse
list/set/mapempty
objectobject with defaults for nested fields
Optional, not requirednull

This means attributes like id and arn receive the string "foo". If two references both read from different aws_s3_bucket.X.id resources, they both get the same "foo". Any logic that depends on uniqueness will break. The fix: set defaults for each resource.

Pitfalls

  • Mocks only work inside *.tftest.hcl. Plain .tf files have no mock_provider block. You cannot "test with terraform plan by hand". Use terraform test.

  • Attributes computed by complex provider logic are not modeled. aws_iam_policy_document is a data source that renders JSON locally. A mock returns a placeholder JSON blob, not a valid policy. To verify IAM policies you need the real data source or an explicit override for every field.

  • Mock defaults are not fixtures. They do not persist state across run blocks. If the first run modifies aws_s3_bucket.this, the second run gets the mock default again, not the modified value. The test runner likes this behavior; the test author sometimes does not.

  • override_resource uses the module-local address. Write aws_s3_bucket.this, not module.X.aws_s3_bucket.this. The assumption is that the test runs from the module's own directory.

  • A provider-level mock does not cover sources declared in a provider with a different alias. For aws.eu you need a separate mock_provider "aws" { alias = "eu" }.

§ команды

bash
terraform test

Standard run. With mock_provider it finishes in seconds.

bash
terraform test -verbose

Shows which overrides were applied on each run.

bash
terraform plan -input=false

Mock blocks are ignored outside tests. This plan goes to the real provider.

§ см. также

  • tf-test-frameworkNative test framework: .tftest.hcl, run, and assertSince version 1.6, Terraform ships a built-in test runner. Files named `*.tftest.hcl` describe scenarios through `run` blocks (each a mini plan or apply) and `assert` checks. The `terraform test` command runs all of them and reports pass/fail. No cloud account is required: with `command = plan` the runner evaluates expressions against plan output and creates no resources.
  • iac-testing-theoryWhat to Test in Terraform, and What to SkipInfrastructure is not an application, so do not apply the test pyramid literally. Test module contracts, business rules, complex expressions, and refactors that should produce no destroy. Do not test that the provider works, that the AWS API returns 200, or that a trivial `name = var.name` holds. The goal is to catch regressions, not to prove correctness.
  • tf-data-sourcedata block: reading what already exists in the clouddata is a block that queries existing infrastructure and returns its attributes to HCL. Terraform creates nothing; it only reads. Use it to reference resources that were not created by Terraform or that live in a different project.
  • localstack-providerLocalStack: a learning AWS that lives in DockerLocalStack emulates the AWS API locally, inside a Docker container. Terraform thinks it is talking to real AWS, but no real resources are created and no money is spent. Ideal for learning and tests.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies