How to Use mock_provider in Terraform Tests (.tftest.hcl)
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
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 = applyagainst 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
- Add a
mock_provider "aws" {}block at the top of your.tftest.hclfile (one per provider you need to fake). - Write a
runblock withcommand = planfor pure logic checks; usecommand = applyonly when you need computed values resolved through the mock. - Set
variables { ... }inside eachrunto feed inputs, matching your module’s variable names exactly. - Add
assertblocks referencing resources (aws_s3_bucket.this.bucket) and outputs (output.bucket_arn). - Pin non-deterministic attributes with
override_resource/override_datawhen an assertion needs an exact ARN, ID, or timestamp. - Run
terraform initthenterraform test, and read the per-runpass/fail lines to locate a failing assertion.
Gotchas
- Mocks are not real validation. A
mock_providerwill 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
awsandrandom, you needmock_provider "aws" {}andmock_provider "random" {}(or a real one for whichever you want live). command = applystill creates nothing with a mock, but it does resolve the full dependency graph, which surfaces different errors thanplan.- File discovery. Tests must live in the root working directory or in
tests/. A stray.tftest.hclin 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.
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.