/provider-test-patterns
Terraform provider acceptance test patterns using terraform-plugin-testing with the Plugin Framework. Covers test structure, TestCase/TestStep fields, ConfigStateChecks with custom statecheck.StateCheck implementations, plan checks, CompareValue for cross-step assertions, config
$ npx -y skills add hashicorp/agent-skills --skill provider-test-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/provider-test-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
Terraform provider acceptance test patterns using terraform-plugin-testing with the Plugin Framework. Covers test structure, TestCase/TestStep fields, ConfigStateChecks with custom statecheck.StateCheck implementations, plan checks, CompareValue for cross-step assertions, config
SKILL.md
provider-test-patterns.SKILL.mdname: provider-test-patterns
description: >-
Terraform provider acceptance test patterns using terraform-plugin-testing
with the Plugin Framework. Covers test structure, TestCase/TestStep fields,
ConfigStateChecks with custom statecheck.StateCheck implementations,
plan checks, CompareValue for cross-step assertions, config helpers,
import testing with ImportStateKind, sweepers, and scenario patterns
(basic, update, disappears, validation, regression), and ephemeral resource
testing with the echoprovider package. Use when writing, reviewing, or
debugging provider acceptance tests, including questions about statecheck,
plancheck, TestCheckFunc, CheckDestroy, ExpectError, import state
verification, ephemeral resources, or how to structure test files.
metadata:
copyright: Copyright IBM Corp. 2026
version: "0.0.1"
Provider Acceptance Test Patterns
Patterns for writing acceptance tests using [terraform-plugin-testing](https://github.com/hashicorp/terraform-plugin-testing) with the [Plugin Framework](https://github.com/hashicorp/terraform-plugin-framework).
Source: [HashiCorp Testing Patterns](https://developer.hashicorp.com/terraform/plugin/testing/testing-patterns)
**References** (load when needed):
- `references/checks.md` — statecheck, plancheck, knownvalue types, tfjsonpath, comparers
- `references/sweepers.md` — sweeper setup, TestMain, dependencies
- `references/ephemeral.md` — ephemeral resource testing, echoprovider, multi-step patterns
---
Test Lifecycle
The framework runs each TestStep through: **plan → apply → refresh → final plan**. If the final plan shows a diff, the test fails (unless `ExpectNonEmptyPlan` is set). After all steps, destroy runs followed by `CheckDestroy`. This means every test automatically verifies that configurations apply cleanly and produce no drift — no assertions needed for that.
---
Test Function Structure
func TestAccExample_basic(t *testing.T) {
var widget example.Widget
rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
resourceName := "example_widget.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
CheckDestroy: testAccCheckExampleDestroy,
Steps: []resource.TestStep{
{
Config: testAccExampleConfig_basic(rName),
ConfigStateChecks: []statecheck.StateCheck{
stateCheckExampleExists(resourceName, &widget),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("name"), knownvalue.StringExact(rName)),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("id"), knownvalue.NotNull()),
},
},
},
})
}Use `resource.ParallelTest` by default. Use `resource.Test` only when tests share state or cannot run concurrently.
---
Provider Factory
// provider_test.go — Plugin Framework with Protocol 6 (use Protocol5 variant if needed)
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"example": providerserver.NewProtocol6WithError(New("test")()),
}---
TestCase Fields
| Field | Purpose | |-------|---------| | `PreCheck` | `func()` — verify prerequisites (env vars, API access) | | `ProtoV6ProviderFactories` | Plugin Framework provider factories | | `CheckDestroy` | `TestCheckFunc` — verify resources destroyed after all steps | | `Steps` | `[]TestStep` — sequential test operations | | `TerraformVersionChecks` | `[]tfversion.TerraformVersionCheck` — gate by CLI version |
---
TestStep Fields
Config Mode
| Field | Purpose | |-------|---------| | `Config` | Inline HCL string to apply | | `ConfigStateChecks` | `[]statecheck.StateCheck` — modern assertions (preferred) | | `ConfigPlanChecks` | `resource.ConfigPlanChecks{PreApply: []plancheck.PlanCheck{...}}` | | `ExpectError` | `*regexp.Regexp` — expect failure matching pattern | | `ExpectNonEmptyPlan` | `bool` — expect non-empty plan after apply | | `PlanOnly` | `bool` — plan without applying | | `Destroy` | `bool` — run destroy step | | `PreConfig` | `func()` — setup before step |
Import Mode
| Field | Purpose | |-------|---------| | `ImportState` | `true` to enable import mode | | `ImportStateVerify` | Verify imported state matches prior state | | `ImportStateVerifyIgnore` | `[]string` — attributes to skip during verify | | `ImportStateKind` | `resource.ImportBlockWithID` — import block generation | | `ResourceName` | Resource address to import | | `ImportStateId` | Override the ID used for import |
---
Check Functions
Modern: ConfigStateChecks (preferred)
Type-safe with aggregated error reporting. Compose built-in checks with custom `statecheck.StateCheck` implementations. See `references/checks.md` for full knownvalue types, tfjsonpath navigation, and comparers.
ConfigStateChecks: []statecheck.StateCheck{
stateCheckExampleExists(resourceName, &widget),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("name"), knownvalue.StringExact("my-widget")),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("enabled"), knownvalue.Bool(true)),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("id"), knownvalue.NotNull()),
statecheck.ExpectSensitiveValue(resourceName,
tfjsonpath.New("api_key")),
},Do not mix `Check` (legacy) and `ConfigStateChecks` in the same step.
Legacy: Check (for CheckDestroy and migration)
`CheckDestroy` on `TestCase` requires `TestCheckFunc`. The `Check` field on `TestStep` also accepts `TestCheckFunc` but prefer `ConfigStateChecks` for new tests.
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(name, "key", "expected"),
resource.TestCheckResourceRead more
name: provider-test-patterns description: >- Terraform provider acceptance test patterns using terraform-plugin-testing with the Plugin Framework. Covers test structure, TestCase/TestStep fields, ConfigStateChecks with custom statecheck.StateCheck implementations, plan checks, CompareValue for cross-step assertions, config helpers, import testing with ImportStateKind, sweepers, and scenario patterns (basic, update, disappears, validation, regression), and ephemeral resource testing with the echoprovider package. Use when writing, reviewing, or debugging provider acceptance tests, including questions about statecheck, plancheck, TestCheckFunc, CheckDestroy, ExpectError, import state verification, ephemeral resources, or how to structure test files. metadata: copyright: Copyright IBM Corp. 2026 version: "0.0.1"
Provider Acceptance Test Patterns
Patterns for writing acceptance tests using [terraform-plugin-testing](https://github.com/hashicorp/terraform-plugin-testing) with the [Plugin Framework](https://github.com/hashicorp/terraform-plugin-framework).
Source: [HashiCorp Testing Patterns](https://developer.hashicorp.com/terraform/plugin/testing/testing-patterns)
**References** (load when needed):
- `references/checks.md` — statecheck, plancheck, knownvalue types, tfjsonpath, comparers
- `references/sweepers.md` — sweeper setup, TestMain, dependencies
- `references/ephemeral.md` — ephemeral resource testing, echoprovider, multi-step patterns
---
Test Lifecycle
The framework runs each TestStep through: **plan → apply → refresh → final plan**. If the final plan shows a diff, the test fails (unless `ExpectNonEmptyPlan` is set). After all steps, destroy runs followed by `CheckDestroy`. This means every test automatically verifies that configurations apply cleanly and produce no drift — no assertions needed for that.
---
Test Function Structure
func TestAccExample_basic(t *testing.T) {
var widget example.Widget
rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
resourceName := "example_widget.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
CheckDestroy: testAccCheckExampleDestroy,
Steps: []resource.TestStep{
{
Config: testAccExampleConfig_basic(rName),
ConfigStateChecks: []statecheck.StateCheck{
stateCheckExampleExists(resourceName, &widget),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("name"), knownvalue.StringExact(rName)),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("id"), knownvalue.NotNull()),
},
},
},
})
}Use `resource.ParallelTest` by default. Use `resource.Test` only when tests share state or cannot run concurrently.
---
Provider Factory
// provider_test.go — Plugin Framework with Protocol 6 (use Protocol5 variant if needed)
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"example": providerserver.NewProtocol6WithError(New("test")()),
}---
TestCase Fields
| Field | Purpose | |-------|---------| | `PreCheck` | `func()` — verify prerequisites (env vars, API access) | | `ProtoV6ProviderFactories` | Plugin Framework provider factories | | `CheckDestroy` | `TestCheckFunc` — verify resources destroyed after all steps | | `Steps` | `[]TestStep` — sequential test operations | | `TerraformVersionChecks` | `[]tfversion.TerraformVersionCheck` — gate by CLI version |
---
TestStep Fields
Config Mode
| Field | Purpose | |-------|---------| | `Config` | Inline HCL string to apply | | `ConfigStateChecks` | `[]statecheck.StateCheck` — modern assertions (preferred) | | `ConfigPlanChecks` | `resource.ConfigPlanChecks{PreApply: []plancheck.PlanCheck{...}}` | | `ExpectError` | `*regexp.Regexp` — expect failure matching pattern | | `ExpectNonEmptyPlan` | `bool` — expect non-empty plan after apply | | `PlanOnly` | `bool` — plan without applying | | `Destroy` | `bool` — run destroy step | | `PreConfig` | `func()` — setup before step |
Import Mode
| Field | Purpose | |-------|---------| | `ImportState` | `true` to enable import mode | | `ImportStateVerify` | Verify imported state matches prior state | | `ImportStateVerifyIgnore` | `[]string` — attributes to skip during verify | | `ImportStateKind` | `resource.ImportBlockWithID` — import block generation | | `ResourceName` | Resource address to import | | `ImportStateId` | Override the ID used for import |
---
Check Functions
Modern: ConfigStateChecks (preferred)
Type-safe with aggregated error reporting. Compose built-in checks with custom `statecheck.StateCheck` implementations. See `references/checks.md` for full knownvalue types, tfjsonpath navigation, and comparers.
ConfigStateChecks: []statecheck.StateCheck{
stateCheckExampleExists(resourceName, &widget),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("name"), knownvalue.StringExact("my-widget")),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("enabled"), knownvalue.Bool(true)),
statecheck.ExpectKnownValue(resourceName,
tfjsonpath.New("id"), knownvalue.NotNull()),
statecheck.ExpectSensitiveValue(resourceName,
tfjsonpath.New("api_key")),
},Do not mix `Check` (legacy) and `ConfigStateChecks` in the same step.
Legacy: Check (for CheckDestroy and migration)
`CheckDestroy` on `TestCase` requires `TestCheckFunc`. The `Check` field on `TestStep` also accepts `TestCheckFunc` but prefer `ConfigStateChecks` for new tests.
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(name, "key", "expected"),
resource.TestCheckResourceA collection of Agent skills and Claude Code plugins for HashiCorp products. Legal Note: Your use of a third party MCP Client/LLM is subject solely to the terms of use for such MCP/LLM, and IBM is not responsible for the performance of such third party tools.
Repo: hashicorp/agent-skills
Other skills on hashicorp-agent-skills.
- /aws-ami-builder
Build Amazon Machine Images (AMIs) with Packer using the amazon-ebs builder. Use when creating custom AMIs for EC2 instances.
Open skill - /azure-image-builder
Build Azure managed images and Azure Compute Gallery images with Packer. Use when creating custom images for Azure VMs.
Open skill - /windows-builder
Build Windows images with Packer using WinRM communicator and PowerShell provisioners. Use when creating Windows AMIs, Azure images, or VMware templates.
Open skill - /push-to-registry
Push Packer build metadata to HCP Packer registry for tracking and managing image lifecycle. Use when integrating Packer builds with HCP Packer for version control and governance.
Open skill - /azure-verified-modules
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
Open skill - /terraform-search-import
Discover existing cloud resources using Terraform Search queries and bulk import them into Terraform management. Use when bringing unmanaged infrastructure under Terraform control, auditing cloud resources, or migrating to IaC.
Open skill

