Skip to content
Development
Skill

/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

From plugin
hashicorp-agent-skills
79017 skills
Install
$ npx -y skills add hashicorp/agent-skills --skill provider-test-patterns --agent claude-code

How 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.md
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.TestCheckResource
Read more
Ships withhashicorp-agent-skills

A 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.

Get the whole plugin
Stats
791
Stars
118
Forks
Active
Maintenance
HCL
Language
MPL-2.0
License
5d ago
Last commit
9mo ago
Created

Repo: hashicorp/agent-skills