---
page_title: 'Testing Migration: Migrating from SDKv2 to the Framework'
description: >-
  Write tests that verify that switching from SDKv2 to the Framework does not affect provider behavior.
---

# Testing

During migration, you should [write tests](#testing-migration) to verify that the behaviour of your provider has not
been altered by the migration itself. You will also need to [update](#provider-factories) your tests too.

<Tip>

  If [muxing](/terraform/plugin/framework/migrating/mux), only migrated resources and data sources require immediate updates of testing code.

</Tip>

## Testing Migration

During migration, we recommend writing tests to verify that switching from SDKv2 to the Framework has not affected your
provider's behavior. These tests use identical configuration. The first test step applies a plan and generates state
with the SDKv2 version of the provider. The second test step generates a plan with the Framework version of the provider
and verifies that the plan is a no-op, indicating that migrating to the framework has not altered behaviour.

Use the `ExternalProviders` field within a `resource.TestStep` to specify the configuration of a specific provider to
use during each test step. You can specify a version of the provider built on SDKv2 during the first test step, and
then you can use the version of the provider built on the Framework in subsequent test step(s) to verify that Terraform
CLI does not detect any planned changes.

You must also update the [provider factories](#provider-factories) to use
the Framework.

### Example

These examples show how you can use external providers to generate state with a previous version of the provider
and then verify that there are no planned changes after migrating to the Framework.

- The first `TestStep` uses `ExternalProviders` to cause `terraform apply` to execute with a previous version of the
provider, which is built on SDKv2.
- The second `TestStep` uses `ProtoV5ProviderFactories` so that the test uses the provider code contained within the
provider repository. The second step uses `ConfigPlanChecks` to verify that a no-op plan is generated.

#### Managed Resource

In this example configuration, all managed resource attribute values are compared between the SDK and Framework implementations:

```go
func TestResource_UpgradeFromVersion(t *testing.T) {
    /* ... */
    resource.Test(t, resource.TestCase{
        Steps: []resource.TestStep{
            {
                ExternalProviders: map[string]resource.ExternalProvider{
                    "<provider>": {
                        VersionConstraint: "<sdk_version>",
                        Source:            "hashicorp/<provider>",
                    },
                },
                Config: `resource "provider_resource" "example" {
                            /* ... */
                        }`,
                Check: resource.ComposeTestCheckFunc(
                    resource.TestCheckResourceAttr("provider_resource.example", "<attribute>", "<value>"),
                    /* ... */
                ),
            },
            {
                ProtoV5ProviderFactories: protoV5ProviderFactories(),
                Config: `resource "provider_resource" "example" {
                            /* ... */
                        }`,
                // ConfigPlanChecks is a terraform-plugin-testing feature.
                // If acceptance testing is still using terraform-plugin-sdk/v2,
                // use `PlanOnly: true` instead. When migrating to
                // terraform-plugin-testing, switch to `ConfigPlanChecks` or you
                // will likely experience test failures.
                ConfigPlanChecks: resource.ConfigPlanChecks{
                    PreApply: []plancheck.PlanCheck{
                        plancheck.ExpectEmptyPlan(),
                    },
                },
            },
        },
    })
}
```

#### Data Source

<Tip>

Prefer individually testing all attribute values of a data source instead of this testing pattern. Testing individual attribute values will catch unexpected data handling changes after migration and prevent any expected introduction of new attributes from causing test failures when using this pattern.

</Tip>

Since data sources are refreshed every Terraform plan and do not use prior state during planning, additional configuration of a separate managed resource or output value is required to track value differences. The [`terraform_data` managed resource](/terraform/language/resources/terraform-data) is one option that is implicitly available for configurations in Terraform 1.4 and later. If testing on older versions of Terraform is required, use the [`null_resource` managed resource](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) with an associated `ExternalProviders` step configuration instead.

In this example configuration, all data source attribute values are compared between the SDK and Framework implementations:

```go
func TestDataSource_UpgradeFromVersion(t *testing.T) {
    /* ... */
    resource.Test(t, resource.TestCase{
        Steps: []resource.TestStep{
            {
                ExternalProviders: map[string]resource.ExternalProvider{
                    "<provider>": {
                        VersionConstraint: "<sdk_version>",
                        Source:            "hashicorp/<provider>",
                    },
                },
                Config: `data "provider_datasource" "test" {
                            /* ... */
                        }
                        
                        resource "terraform_data" "test" {
                            input = data.provider_datasource.test
                        }`,
            },
            {
                ProtoV5ProviderFactories: protoV5ProviderFactories(),
                Config: `data "provider_datasource" "test" {
                            /* ... */
                        }
                        
                        resource "terraform_data" "test" {
                            input = data.provider_datasource.test
                        }`,
                // ConfigPlanChecks is a terraform-plugin-testing feature.
                // If acceptance testing is still using terraform-plugin-sdk/v2,
                // use `PlanOnly: true` instead. When migrating to
                // terraform-plugin-testing, switch to `ConfigPlanChecks` or you
                // will likely experience test failures.
                ConfigPlanChecks: resource.ConfigPlanChecks{
                    PreApply: []plancheck.PlanCheck{
                        plancheck.ExpectEmptyPlan(),
                    },
                },
            },
        },
    })
}
```

## Provider Factories

Existing tests should require minimal updates when migrating from SDKv2 to the Framework. The only critical change
relates to the provider factories that create the provider during the test case. Refer to [Acceptance Tests - Specify Providers](/terraform/plugin/framework/acctests#specify-providers) in the Framework
documentation for details.

We also recommend writing tests that verify that switching from SDKv2 to the Framework has not affected provider
behavior. Refer to [Testing Migration](#testing-migration) for details.

### SDKv2

In SDKv2, you use the `ProviderFactories` field on the `resource.TestCase` struct to obtain `schema.Provider`.

The following example shows a test written in SDKv2.

```go
resource.UnitTest(t, resource.TestCase{
    ProviderFactories: testProviders(),
```

### Framework

In the Framework, use either the `ProtoV5ProviderFactories` or `ProtoV6ProviderFactories` field on the
`resource.TestCase` struct to obtain the `provider.Provider`, depending on the
[Terraform Plugin Protocol](/terraform/plugin/how-terraform-works#terraform-plugin-protocol) version your provider is using.

The following example shows how you can write a test in the Framework for a Provider that uses protocol version 6.

```go
resource.UnitTest(t, resource.TestCase{
    ProtoV6ProviderFactories: protoV6ProviderFactories(),
```

### Example

#### SDKv2

The following code sample shows how to define provider factories within a test case when using SDKv2.

```go
func TestDataSource_Exmple(t *testing.T) {
    /* ... */
    resource.UnitTest(t, resource.TestCase{
        ProviderFactories: testProviders(),
        /* ... */
    })
}
```

The following  shows how to generate provider factories when using SDKv2.

```go
func testProviders() map[string]func() (*schema.Provider, error) {
    return map[string]func() (*schema.Provider, error){
        "example": func() (*schema.Provider, error) { return New(), nil },
    }
}
```

#### Framework

The following shows how to define provider factories within a test case when using the Framework.

```go
func TestDataSource_Example(t *testing.T) {
    /* ... */

    resource.UnitTest(t, resource.TestCase{
        ProtoV5ProviderFactories: protoV5ProviderFactories(),
        /* ... */
    })
}
```

The following shows how to generate provider factories when using
the Framework. The call to `New` returns an instance of the provider. Refer to
[Provider Definition](/terraform/plugin/framework/migrating/providers#provider-definition) in this guide for details.

```go
func protoV5ProviderFactories() map[string]func() (tfprotov5.ProviderServer, error) {
    return map[string]func() (tfprotov5.ProviderServer, error){
        "example": providerserver.NewProtocol5WithError(New()),
    }
}
```
