June 20-22 Announcing HashiConf Europe full schedule: keynotes, sessions, labs & more Register Now
  • Overview
    • Enforce Policy as Code
    • Infrastructure as Code
    • Inject Secrets into Terraform
    • Integrate with Existing Workflows
    • Manage Kubernetes
    • Manage Network Infrastructure
    • Manage Virtual Machine Images
    • Multi-Cloud Deployment
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
  • Registry
  • Tutorials
    • About the Docs
    • Intro to Terraform
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
    • Terraform Tools
    • CDK for Terraform
    • Glossary
  • Community
GitHubTerraform Cloud
Download

    SDKv2

  • Overview
  • Tutorials: Custom Providers
    • Overview
    • Schema Types
    • Schema Behaviors
    • Schema Methods
    • Overview
    • Customizing Differences
    • Import
    • Retries and Customizable Timeouts
    • State Migration
  • Debugging Providers
    • Compatibility with Terraform 0.12
    • Switching to the standalone SDK
    • v2 Upgrade Guide
    • Overview
    • Naming
    • Depending on Providers
    • Deprecations, Removals, and Renames
    • Detecting Drift
    • Handling Sensitive Data
    • Testing Patterns
    • Versioning and Changelog
    • Writing Non-Go Providers
    • Overview
      • Overview
      • Test Cases
      • Test Steps
      • Sweepers
    • Testing API
    • Testing Patterns
    • Unit Testing
  • Other Plugin Docs

  • Plugin Development
  • Framework
  • Logging
  • Combining and Translating
Type '/' to Search

»Unit Testing

Testing plugin code in small, isolated units is distinct from Acceptance Tests, and does not require network connections. Unit tests are commonly used for testing helper methods that expand or flatten API responses into data structures for storage into state by Terraform. This section covers the specifics of writing Unit Tests for Terraform Plugin code.

The procedure for writing unit tests for Terraform follows the same setup and conventions of writing any Go unit tests. We recommend naming tests to follow the same convention as our acceptance tests, Test<Provider>_<Test Name>. For more information on Go tests, see the official Golang docs on testing.

Below is an example unit test used in flattening AWS security group rules, demonstrating a typical flattener type method that's commonly used to convert structures returned from APIs into data structures used by Terraform in saving to state. This example is truncated for brevity, but you can see the full test in the aws/structure_test.go in the Terraform AWS Provider repository on GitHub

func TestFlattenSecurityGroups(t *testing.T) {
    cases := []struct {
        ownerId  *string
        pairs    []*ec2.UserIdGroupPair
        expected []*GroupIdentifier
    }{
        // simple, no user id included
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId: aws.String("sg-12345"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId: aws.String("sg-12345"),
                },
            },
        },
        // include the owner id, but keep it consitent with the same account. Tests
        // EC2 classic situation
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId: aws.String("sg-12345"),
                    UserId:  aws.String("user1234"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId: aws.String("sg-12345"),
                },
            },
        },

        // include the owner id, but from a different account. This is reflects
        // EC2 Classic when referring to groups by name
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId:   aws.String("sg-12345"),
                    GroupName: aws.String("somegroup"), // GroupName is only included in Classic
                    UserId:    aws.String("user4321"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId:   aws.String("sg-12345"),
                    GroupName: aws.String("user4321/somegroup"),
                },
            },
        },
    }

    for _, c := range cases {
        out := flattenSecurityGroups(c.pairs, c.ownerId)
        if !reflect.DeepEqual(out, c.expected) {
            t.Fatalf("Error matching output and expected: %#v vs %#v", out, c.expected)
        }
    }
}
func TestFlattenSecurityGroups(t *testing.T) {
    cases := []struct {
        ownerId  *string
        pairs    []*ec2.UserIdGroupPair
        expected []*GroupIdentifier
    }{
        // simple, no user id included
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId: aws.String("sg-12345"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId: aws.String("sg-12345"),
                },
            },
        },
        // include the owner id, but keep it consitent with the same account. Tests
        // EC2 classic situation
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId: aws.String("sg-12345"),
                    UserId:  aws.String("user1234"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId: aws.String("sg-12345"),
                },
            },
        },

        // include the owner id, but from a different account. This is reflects
        // EC2 Classic when referring to groups by name
        {
            ownerId: aws.String("user1234"),
            pairs: []*ec2.UserIdGroupPair{
                &ec2.UserIdGroupPair{
                    GroupId:   aws.String("sg-12345"),
                    GroupName: aws.String("somegroup"), // GroupName is only included in Classic
                    UserId:    aws.String("user4321"),
                },
            },
            expected: []*GroupIdentifier{
                &GroupIdentifier{
                    GroupId:   aws.String("sg-12345"),
                    GroupName: aws.String("user4321/somegroup"),
                },
            },
        },
    }

    for _, c := range cases {
        out := flattenSecurityGroups(c.pairs, c.ownerId)
        if !reflect.DeepEqual(out, c.expected) {
            t.Fatalf("Error matching output and expected: %#v vs %#v", out, c.expected)
        }
    }
}
github logoEdit this page
  • Overview
  • Docs
  • Extend
  • Privacy
  • Security
  • Press Kit
  • Consent Manager