A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.hashicorp.com/terraform/language/v1.7.x/tests/mocking below:

Tests - Provider Mocking | Terraform

Note: Test mocking is available in Terraform v1.7.0 and later. This feature is in beta.

Terraform lets you mock providers, resources, and data sources for your tests. This allows you to test parts of your module without creating infrastructure or requiring credentials. In a Terraform test, a mocked provider or resource will generate fake data for all computed attributes that would normally be provided by the underlying provider APIs.

Mocking functionality can only be used with the terraform test language. Readers of this documentation should be familiar with the testing syntax and language features.

In addition, the more advanced features of the mocking framework require knowledge about the following Terraform provider features:

In Terraform tests, you can mock a provider with the mock_provider block. Mock providers return the same schema as the original provider and you can pass the mocked provider to your tests in place of the matching provider. All resources and data sources retrieved by a mock provider will set the relevant values from the configuration, and generate fake data for any computed attributes.

Mock providers can be used directly in place of traditional provider blocks and they share the same global namespace. During the execution of the terraform test command, Terraform does not distinguish between a real and a mocked provider.

The following example creates an AWS S3 bucket and then uses a mocked provider to test the configuration without requiring an AWS account.

# main.tf

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

variable "bucket_name" {
  type = string
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = var.bucket_name
}
# bucket_name.tftest.hcl

mock_provider "aws" {}

run "sets_correct_name" {
  variables {
    bucket_name = "my-bucket-name"
  }

  assert {
    condition     = aws_s3_bucket.my_bucket.bucket == "my-bucket-name"
    error_message = "incorrect bucket name"
  }
}

From the perspective of a plan or apply operation executed in a Terraform test file, the mocked provider is creating actual resources with values that match the configuration. These resources are stored in the Terraform state files that terraform test creates and holds in memory during test executions.

You can use mocked providers and real providers simulating in a Terraform test. The following example defines two AWS providers, one real and one mocked. You must provide an alias to one of them, as they share the same global aws provider namespace. You can then use the providers attribute in test run blocks to customize which AWS provider to use for each run block.

# mocked_providers.tftest.hcl

provider "aws" {}

mock_provider "aws" {
  alias = "fake"
}

run "use_real_provider" {
  providers = {
    aws = aws
  }
}

run "use_mocked_provider" {
  providers = {
    aws = aws.fake
  }
}
Generated data

A mocked provider will generate data for any computed attributes in referenced data sources or attributes. For example, the arn attribute is a unique identifier generated by AWS for most resources. A mocked aws provider will provide a value for this attribute in any resources it creates.

Note: Mocked providers do not have any information about the expected format of the computed attributes, so the generated data will rarely match any expected syntax that real providers would return for those attributes.

Mocked providers only generate data for computed attributes. All required resource attributes must be set when you use a mocked provider. If you do not provide a value for an optional computed attribute, Terraform will automatically generate one. The values that Terraform generates depends on the data type:

An example of this is the bucket attribute in the aws_s3_bucket resource. A real AWS provider will generate a bucket name if one is not specified. A mocked AWS provider will do the same, and only generate a value if one is not already specified in the configuration.

Mock Provider data

You can specify specific values for targeted resources and data sources. in a mock_provider block, you can write any number of mock_resource and mock_data blocks. Both the mock_resource and mock_data blocks accept a type argument that should match the resource or data source you want to provide values for. They also accept a defaults object attribute that you can use to specify the values that should be returned for specific attributes.

The following example demonstrates providing a set arn value for all AWS S3 bucket resources and data sources:

mock_provider "aws" {
  mock_resource "aws_s3_bucket" {
    defaults = {
      arn = "arn:aws:s3:::name"
    }
  }

  mock_data "aws_s3_bucket" {
    defaults = {
      arn = "arn:aws:s3:::name"
    }
  }
}

In the above example, Terraform uses the supplied value for arn attributes in S3 buckets instead of generating a random string. Computed attributes not provided an explicit default will simply fall back to the generic data generation rules.

You can also share mock provider data between tests by writing dedicated mock data files and using the source attribute in the mock_provider block. Mock data files have .tfmock.hcl or .tfmock.json extension, and can contain mock_resource and mock_data blocks as if they were defined in the mock_provider block directly.

# ./testing/aws/data.tfmock.hcl

mock_resource "aws_s3_bucket" {
  defaults = {
    arn = "arn:aws:s3:::name"
  }
}

mock_data "aws_s3_bucket" {
  defaults = {
    arn = "arn:aws:s3:::name"
  }
}
mock_provider "aws" {
  source = "./testing/aws"
}

The above example defines mock_resource and mock_data blocks in a mock data file located at ./testing/aws. You can load multiple test files and share the same mock provider data without copying the same definitions across multiple files.

You can combine the source attribute with directly nested mock_resource and mock_data blocks. If the source location and a directly nested block describe the same resource or data source then the directly nested block takes precedence.

In addition to mocking providers, you can use the following block types to override specific resources, data sources, and modules:

All three blocks can be placed at the root level of Terraform test files and in Terraform test file run blocks. In addition, the override_resource and override_data blocks can be nested in mock_provider blocks and in Terraform mock data files.

Overrides can be used with both real and mocked providers and will provide the computed values instead of the underlying provider.

Overrides Syntax

All override blocks contain a target attribute, which should specify the resource, data source, or module to override. The override_module blocks contain an outputs attribute, while the override_resource and override_data blocks contain a values attribute.

The outputs and values attributes are optional and if not specified, Terraform will generate values for them automatically.

The following example demonstrates the override blocks at various different scopes and levels. The main configuration calls the ./modules/s3_data module to read a file from an S3 bucket, and then creates a local_file from the data returned from the module.

# main.tf

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

module "credentials" {
  source = "./modules/s3_data"

  data_bucket_name = "my_company_bucket_name"
}

resource "local_file" "credentials_json" {
  filename = "credentials.json"
  content  = jsonencode(module.credentials.data)
}
# ./modules/s3_data/main.tf

variable "data_bucket_name" {
  type = string
}

data "aws_s3_object" "data_bucket" {
  bucket = var.data_bucket_name
  key    = "credentials.json"
}

output "data" {
  value = jsondecode(data.aws_s3_object.data_bucket.body)
}

Firstly, you can override the aws_s3_bucket_object in the module directly in a mock provider. The following example defines an override_data block in the mock_provider block. In this case, Terraform will only override the target data source if the mock provider creates it.

# main.tftest.hcl

mock_provider "aws" {
  override_data {
    target = module.credentials.data.aws_s3_object.data_bucket
    values = {
      body = "{\"username\":\"username\",\"password\":\"password\"}"
    }
  }
}

run "test" {
  assert {
    condition     = jsondecode(local_file.credentials_json.content).username == "username"
    error_message = "incorrect username"
  }
}

Alternatively, you could also override the same aws_s3_bucket_object in the test file itself, or in a run block. In this case, the underlying provider doesn't matter since Terraform overrides the data source at the target address regardless of the provider. The following example still mocks the provider so that Terraform can run the test without AWS credentials. Override blocks can override resources provided by real providers.

# main.tftest.hcl

mock_provider "aws" {}

override_data {
  target = module.credentials.data.aws_s3_object.data_bucket
  values = {
    body = "{\"username\":\"username\",\"password\":\"password\"}"
  }
}

run "test_file_override" {
  assert {
    condition     = jsondecode(local_file.credentials_json.content).username == "username"
    error_message = "incorrect username"
  }
}

run "test_run_override" {
  # The value in this local override block takes precedence over the
  # alternate defined in the file.
  override_data {
    target = module.credentials.data.aws_s3_object.data_bucket
    values = {
      body = "{\"username\":\"a_different_username\",\"password\":\"password\"}"
    }
  }

  assert {
    condition     = jsondecode(local_file.credentials_json.content).username == "a_different_username"
    error_message = "incorrect username"
  }
}

In the above example, the override block defined at the file level is used in the first run block. Then in the second run block, the alternative local override takes precedence over the file level override.

Finally, you can override the entire module with the override_module block. In the following example, Terraform overrides the entire module instead of specific resources in the module.

# main.tftest.hcl
mock_provider "aws" {}

override_module {
  target = module.credentials
  outputs = {
    data = { username = "username", password = "password" }
  }
}

run "test" {
  assert {
    condition     = jsondecode(local_file.credentials_json.content).username == "username"
    error_message = "incorrect username"
  }
}

In this case, the override block specifies outputs instead of values and the output value is specified as HCL instead of as a string as the real module is passing the data through the jsondecode function. As with override_data blocks, you can also specify the override_module block in the run block and the same precedence rules apply.

Some resources and data sources specify repeated nested attributes as computed directly, while repeated blocks in the resource may also contain computed attributes. For repeated blocks and nested attributes, you cannot specify values for specific instances in the collection. Instead, you must provide a single set of values that apply for all instances in the collection.

For example, the aws_dynamodb_table resource contains a root-level computed arn attribute as well as a set-repeated block called replica which also contains a computed arn attribute. The following is an example of a simple instance of an aws_dynamodb_table.

# main.tf

resource "aws_dynamodb_table" "my_table" {
  name     = "my_table"
  hash_key = "key"

  attribute {
    name = "key"
    type = "S"
  }

  replica {
    region_name = "eu-west-2"
  }

  replica {
    region_name = "us-east-1"
  }
}

Normally, the AWS provider would return ARN values for the DynamoDB table and both of the specified replicas. While a mock_resource block can mimic this behavior, it cannot differentiate between the multiple replica blocks in the resource:

mock_resource "aws_dynamodb_table" {
  defaults = {
    arn = "aws:dynamodb:::my_table"
    replica = {
      arn = "aws:dynamodb:::my_replica"
    }
  }
}

In this case, the mock_resource provides a specific value for the ARN of the DynamoDB table, but the ARN values returned for the replica tables are shared between all instances.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4