4. 测试环境搭建:使用 Terratest、Go 语言环境、AWS/GCP/Azure Provider 模拟器配置

搭建可复现、隔离且低成本的测试环境是模块测试策略的基石。本章将指导你完成三部分核心环境的配置:Go 语言与 Terratest 框架、云 Provider 模拟器(LocalStack / FakeGCS / Azurite),以及测试项目结构的初始化。通过模拟器,你可以在本地运行测试,无需真实云资源,从而大幅提升测试速度与安全性。

4.1 环境全景:测试栈组件与关系

下图展示了测试执行时各组件之间的调用关系与数据流。Terratest 作为测试框架,通过 Go 测试函数调用云 SDK 或 HTTP API,与运行在本地的 Provider 模拟器交互,模拟真实云服务的资源生命周期。

测试环境组件架构图 Go Test Runner go test -v ./test/... Terratest 框架 terraform / http / aws 包 Terraform CLI terraform init & apply LocalStack AWS API 模拟 (S3/EC2/IAM) FakeGCS GCP Storage 模拟 Azurite Azure Blob/Queue/Table 模拟 Docker 容器 (本地运行) 临时文件系统 / 内存 Docker 容器 (本地运行) 说明:所有模拟器均运行在本地 Docker 中,测试通过配置 endpoint 指向 localhost 端口,实现零云成本测试。

4.2 Go 语言环境与 Terratest 安装

Terratest 是一个基于 Go 的测试库,专门用于基础设施代码的自动化测试。它提供了一组帮助函数,用于执行 Terraform 命令、验证云资源状态以及处理 HTTP 响应。

4.2.1 安装 Go 与配置工作区

  1. 下载 Go:访问 go.dev/dl,选择对应操作系统的版本(推荐 1.21+)。
  2. 设置环境变量:确保 GOPATH 和 GOROOT 正确配置,并将 $GOPATH/bin 加入 PATH。
  3. 验证安装:运行 go version 确认输出。
💡 建议:使用 Go Modules 管理依赖。在项目根目录执行 go mod init github.com/your-org/terraform-module-tests 初始化模块。

4.2.2 安装 Terratest

在测试目录下执行以下命令,将 Terratest 添加为依赖:

cd test
go get github.com/gruntwork-io/terratest/modules/terraform
go get github.com/gruntwork-io/terratest/modules/aws
go get github.com/gruntwork-io/terratest/modules/http-helper

Terratest 的核心包功能如下表所示:

包路径 核心功能 典型使用场景
modules/terraform 执行 init、apply、destroy、output 部署与销毁测试环境
modules/aws 封装 AWS SDK 调用(S3、EC2、IAM) 验证 AWS 资源状态
modules/http-helper 发送 HTTP 请求并断言响应 测试 API Gateway / ALB 端点
modules/files 文件与目录操作 复制 Terraform 配置到临时目录
modules/logger 结构化日志输出 调试测试执行过程

4.3 Provider 模拟器配置

模拟器允许你在本地模拟云服务 API,避免真实资源费用和网络延迟。以下分别介绍 AWS、GCP、Azure 三种模拟器的配置方法。

4.3.1 LocalStack(AWS 模拟器)

LocalStack 是最成熟的 AWS 模拟器,支持 S3、DynamoDB、Lambda、EC2 等核心服务。使用 Docker Compose 启动:

# docker-compose.yml
version: "3.8"
services:
  localstack:
    image: localstack/localstack:latest
    ports:
      - "4566:4566"            # 主网关端口
    environment:
      - SERVICES=s3,iam,ec2    # 按需启用服务
      - AWS_DEFAULT_REGION=us-east-1
      - EDGE_PORT=4566
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

启动后,在 Terratest 测试中配置 AWS endpoint:

awsSession := aws.NewSession(t, &aws.Config{
  Region:      aws.String("us-east-1"),
  Endpoint:    aws.String("http://localhost:4566"),
  Credentials: credentials.NewStaticCredentials("fake", "fake", ""),
  S3ForcePathStyle: aws.Bool(true),
})
⚠️ 注意:LocalStack 默认使用 S3ForcePathStyle,否则路径解析会出错。IAM 策略模拟存在部分限制,复杂策略建议在真实环境验证。

4.3.2 FakeGCS(GCP Storage 模拟器)

FakeGCS 是一个轻量级的 GCS 模拟器,支持 Bucket 创建、对象上传/下载。使用 Docker 运行:

docker run -d --name fake-gcs \
  -p 4443:4443 \
  -v /tmp/fake-gcs-data:/data \
  fsouza/fake-gcs-server:latest

在 Terratest 中,通过设置 STORAGE_EMULATOR_HOST 环境变量或直接使用自定义 HTTP 客户端来访问:

os.Setenv("STORAGE_EMULATOR_HOST", "http://localhost:4443")
// 之后使用标准 GCP SDK 即可自动指向模拟器

4.3.3 Azurite(Azure 模拟器)

Azurite 是 Azure 存储服务的官方模拟器,支持 Blob、Queue 和 Table。使用 npm 或 Docker 安装:

# 使用 Docker
docker run -d --name azurite \
  -p 10000:10000 \
  -p 10001:10001 \
  -p 10002:10002 \
  mcr.microsoft.com/azure-storage/azurite

端口映射说明:

端口 服务 连接字符串示例
10000 Blob 服务 DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;
10001 Queue 服务 同上,替换 QueueEndpoint
10002 Table 服务 同上,替换 TableEndpoint

4.4 测试项目结构初始化

一个标准的 Terraform 模块测试项目结构如下:

terraform-module/
├── main.tf                 # 模块主入口
├── variables.tf            # 输入变量
├── outputs.tf              # 输出值
├── test/
│   ├── go.mod              # Go 模块定义
│   ├── go.sum              # 依赖锁文件
│   ├── basic_test.go       # 基础功能测试
│   ├── policy_test.go      # 策略合规测试
│   └── fixtures/
│       ├── basic/          # 测试用例的 Terraform 配置
│       │   ├── main.tf
│       │   └── terraform.tfvars
│       └── policy/
│           ├── main.tf
│           └── terraform.tfvars
└── Makefile                # 统一命令入口

4.4.1 编写第一个测试文件

以下是一个使用 LocalStack 模拟器的完整测试示例:

// test/basic_test.go
package test

import (
  "testing"
  "github.com/gruntwork-io/terratest/modules/terraform"
  "github.com/gruntwork-io/terratest/modules/aws"
  "github.com/stretchr/testify/assert"
)

func TestS3BucketCreation(t *testing.T) {
  t.Parallel()

  terraformOptions := &terraform.Options{
    TerraformDir: "../fixtures/basic",
    Vars: map[string]interface{}{
      "bucket_name": "test-bucket-001",
      "region":      "us-east-1",
    },
    EnvVars: map[string]string{
      "AWS_ACCESS_KEY_ID":     "fake",
      "AWS_SECRET_ACCESS_KEY": "fake",
      "AWS_DEFAULT_REGION":    "us-east-1",
    },
  }

  defer terraform.Destroy(t, terraformOptions)
  terraform.InitAndApply(t, terraformOptions)

  // 使用模拟器验证
  awsSession := aws.NewAuthenticatedSession(t, "us-east-1")
  bucketExists := aws.AssertS3BucketExists(t, awsSession, "test-bucket-001")
  assert.True(t, bucketExists, "Bucket should exist after apply")
}

4.4.2 使用 Makefile 统一管理

创建 Makefile 来简化测试执行:

# Makefile
.PHONY: test test-aws test-gcp test-azure

test: test-aws test-gcp test-azure

test-aws:
	cd test && go test -v -run TestAWS -timeout 30m

test-gcp:
	STORAGE_EMULATOR_HOST=http://localhost:4443 \
	cd test && go test -v -run TestGCP -timeout 30m

test-azure:
	AZURITE_ACCOUNT_NAME=devstoreaccount1 \
	AZURITE_ACCOUNT_KEY="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" \
	cd test && go test -v -run TestAzure -timeout 30m
🔑 关键点:模拟器环境变量(如 STORAGE_EMULATOR_HOST、AWS_ENDPOINT_URL)必须在测试执行前设置。建议在 Makefile 或 CI 配置中统一注入,避免硬编码在测试代码中。

4.5 验证环境连通性

完成配置后,运行以下命令验证环境是否正常工作:

# 启动所有模拟器
docker-compose up -d

# 运行测试
cd test && go test -v -run TestS3BucketCreation -timeout 10m

预期输出应包含:

=== RUN   TestS3BucketCreation
    basic_test.go:30: Running terraform init
    basic_test.go:32: Running terraform apply
    basic_test.go:38: Verifying S3 bucket exists
--- PASS: TestS3BucketCreation (12.45s)

如果测试失败,请检查:

  • 模拟器容器是否正常运行(docker ps)
  • 端口映射是否与测试代码中的 endpoint 一致
  • Go 依赖是否完整下载(go mod tidy)

至此,你的测试环境已搭建完成,可以开始编写针对 Terraform 模块的自动化测试用例了。