mock_provider vs override_resource vs override_data in Terraform Tests
Decide between mock_provider, override_resource, and override_data in .tftest.hcl. When to mock a whole provider vs override a single resource or data source in Terraform 1.7+ tests.
- #terraform
- #testing
- #mock_provider
- #troubleshooting
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
The Decision You Are Facing
Terraform 1.7+ ships three overlapping ways to fake infrastructure in a .tftest.hcl file: mock_provider, override_resource, and override_data. They solve related problems, and it is easy to reach for the wrong one, which leads to either brittle tests or tests that still hit real APIs.
Here is the short version:
mock_provider— fake an entire provider. Broad. Use it as your default for offline unit tests.override_resource— pin the computed values of one specific resource. Narrow. Use it for a resource whose real values you need to assert against.override_data— pin the computed values of one specific data source. Narrow. Use it for a single data read (like a lookup orterraform_remote_state).
mock_provider: Fake the Whole Provider
mock_provider replaces every resource and data source for a provider with generated fake values. Computed attributes get placeholder values automatically, so a plan or apply runs completely offline with no credentials.
mock_provider "aws" {}
run "bucket_gets_expected_name" {
command = plan
variables {
environment = "staging"
}
assert {
condition = aws_s3_bucket.logs.bucket == "acme-logs-staging"
error_message = "bucket name did not follow the naming convention"
}
}
Every AWS resource and data source is now mocked. You did not have to enumerate anything. This is the right default when you are testing your own logic (naming, count, conditionals, tags) rather than a specific value returned by the cloud.
You can also seed defaults per resource type inside the block:
mock_provider "aws" {
mock_resource "aws_s3_bucket" {
defaults = {
arn = "arn:aws:s3:::mocked-bucket"
}
}
}
Reach for it when: you want a fully offline unit test and you do not care about the exact values of most computed attributes.
override_resource: Pin One Resource
Sometimes a mock provider gives you a placeholder value, but a downstream expression depends on a specific computed attribute of one resource. override_resource lets you fix that resource’s values precisely, whether or not the provider is mocked.
mock_provider "aws" {}
run "cert_arn_flows_to_listener" {
command = plan
override_resource {
target = aws_acm_certificate.this
values = {
arn = "arn:aws:acm:us-east-1:111111111111:certificate/abc"
}
}
assert {
condition = aws_lb_listener.https.certificate_arn == "arn:aws:acm:us-east-1:111111111111:certificate/abc"
error_message = "listener did not pick up the certificate ARN"
}
}
The target is the resource address; values are the attributes you want to force. Everything else about that resource still comes from the mock. This keeps the broad convenience of mock_provider while making one value deterministic.
Reach for it when: a mocked resource’s auto-generated value is not good enough and a downstream reference needs an exact, known value.
override_data: Pin One Data Source
override_data is the data-source twin of override_resource. It replaces the computed result of a single data block with literals you supply. This is the go-to for external lookups and remote state that you do not want the test to actually perform.
mock_provider "aws" {}
run "ami_lookup_is_deterministic" {
command = plan
override_data {
target = data.aws_ami.ubuntu
values = {
id = "ami-0123456789"
}
}
assert {
condition = aws_instance.web.ami == "ami-0123456789"
error_message = "instance did not use the overridden AMI id"
}
}
The same block works for data.terraform_remote_state.<name>, where you nest the fake values under an outputs key. override_data guarantees the read is offline and the value is fixed.
Reach for it when: a specific data source (an AMI lookup, an IAM policy document, remote state) must return a known value and must not touch a real API.
Side-by-Side Comparison
| Primitive | Scope | Targets | Typical use |
|---|---|---|---|
mock_provider | Whole provider | All resources + data sources | Default offline unit test |
override_resource | One resource | A single resource address | Force a specific computed resource value |
override_data | One data source | A single data address | Force a lookup or remote-state result |
They compose. The idiomatic pattern is a broad mock_provider plus a few surgical override_data / override_resource blocks for the handful of values you actually assert on:
mock_provider "aws" {}
override_data {
target = data.aws_caller_identity.current
values = { account_id = "111111111111" }
}
run "policy_targets_current_account" {
command = plan
assert {
condition = strcontains(aws_iam_policy.app.policy, "111111111111")
error_message = "policy did not reference the mocked account id"
}
}
Scoping: Run-Level vs File-Level
All three override blocks can sit inside a run block (applies to that run only) or at file scope (applies to every run). Put shared fakes at file scope to avoid repetition; keep run-specific values inside the run. mock_provider is always declared at file scope.
terraform test
tests/main.tftest.hcl... in progress
run "policy_targets_current_account"... pass
tests/main.tftest.hcl... pass
Success! 1 passed, 0 failed.
A Simple Rule of Thumb
Start with mock_provider for everything. The moment an assertion depends on an exact value that the mock generates randomly, add an override_resource (for a managed resource) or override_data (for a data source) to pin just that value. Do not enumerate overrides you do not assert against, and do not reach for narrow overrides when a whole-provider mock would do.
For prompt-driven help authoring these blocks, the DevOps AI prompt library has Terraform test templates ready to adapt.
Frequently Asked Questions
When should I use mock_provider vs override_data? Use mock_provider to fake an entire provider so the whole plan runs offline. Use override_data when one specific data source must return a known value. They are complementary: mock broadly, then override the individual data reads you assert against.
What is the difference between override_resource and override_data? override_resource pins the computed values of a managed resource; override_data pins the computed values of a data source. Same syntax (target plus values), different block type. Choose based on whether the address is a resource or a data source.
Do I still need mock_provider if I use override blocks? Usually yes. Override blocks only replace the specific addresses you name. Without mock_provider, every other resource and data source still tries to reach the real API. Mock the provider for full isolation, then override individual values.
Can I use all three in one test file? Yes, and that is the recommended pattern. Declare mock_provider at file scope for broad isolation, then add override_resource and override_data blocks for the exact values your assertions depend on.
Where do override blocks go, in run or at file scope? Either. Put run-specific values inside the run block and shared values at file scope so they apply to every run. mock_provider is always file scope. For more patterns, see the Terraform guides.
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.