news 2026/9/15 20:52:28

Terraform AWS Provider 验收测试与单元测试审查指南:从 `review-tests` 技能看测试规范

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Terraform AWS Provider 验收测试与单元测试审查指南:从 `review-tests` 技能看测试规范

Terraform AWS Provider 验收测试与单元测试审查指南:从review-tests技能看测试规范

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

导读

本篇文章以开源仓库terraform-provider-aws中面向代码审查者的.agents/skills/review-tests/SKILL.md为核心,系统讲解该仓库为「每个资源」制定的一套验收测试(Acceptance Test)与单元测试(Unit Test)基础规范,包括必须存在的_basic/_disappears测试、TestAcc命名规则、TestCase必备字段(PreCheckErrorCheckProtoV5ProviderFactoriesCheckDestroy)、随机命名、ImportState步骤与正则/ARN 断言等。读完本文,你将能独立审查internal/service/**/*_test.go变更,准确识别测试缺失、命名错误与反模式,并能结合源码理解每条规范的底层实现。

适用范围与定位

review-tests是仓库.agents目录下的一组「审查技能」(skills)之一,与 breaking-changes、review-schema、review-tags、review-identity 等并列,通常由review-pr加载,用于审查修改了internal/service/**/*_test.go的 Pull Request。

需要特别说明的是本技能的范围边界:

  • 范围内:按资源(per-resource)维度的验收测试基础要素;
  • 范围外:Ephemeral Resource、Provider Functions、Actions 类测试不在此技能覆盖范围内;
  • 配套技能:Exists/Destroy 检查、数据源(data source)测试、列表资源(list resource)测试以及单元测试的深入内容,由review-tests-helpers技能补充。

在开始逐条规范前,先理解一个整体原则:review-tests假定审查者扮演@maintainer角色,即以维护者视角审视测试代码是否符合仓库长期沉淀的约定。

新资源必须配备的两个测试

SKILL 明确规定:为仓库新增资源时,以下两个测试是硬性要求。

TestAcc<Service><Resource>_basic

这是「完整快乐路径」测试,覆盖资源从创建、读取到属性校验的全过程,并且必须以一个ImportState步骤收尾(Import 步骤规范详见后文)。_basic测试中应当尽可能对全部属性做断言,而不是只检查 ID。

以 EC2 服务的 vpc_test.go 为例,TestAccVPC_basicCheck块使用resource.ComposeAggregateTestCheckFunc一次性断言了 ARN、CIDR、DNS 相关布尔值、实例租期、ipv6_association_id空值、owner ID、tags 等十余个属性,最后以ImportState步骤结尾,是_basic测试的典型范式。

TestAcc<Service><Resource>_disappears

该测试用于验证「资源在 Terraform 之外被删除后,Provider 能否将其重建」。测试思路是:先正常创建资源,然后在Check中调用仓库提供的 disappears 辅助函数带外(out-of-band)删除远端资源,再通过断言产生非空计划(ExpectNonEmptyPlan: true)以及计划动作检查,验证下一次 apply 会重新创建资源。

同样在 vpc_test.go 中可以看到完整的TestAccVPC_disappears:它调用acctest.CheckSDKResourceDisappears删除 VPC,并借助plancheck.ExpectResourceAction断言资源动作应为Create(重建)。值得注意的是,SKILL 还要求:凡是为资源声明了@Tags与 identity 注解的,标签测试(_tags*)与身份测试(_Identity_*)应由生成器自动生成,因此审查 PR 时若发现新资源出现了手写的这类测试,应当标记出来。

测试命名规范

命名是测试可读性与可维护性的第一道关卡。SKILL 给出的命名规则如下:

测试类型命名模板示例
资源验收测试TestAcc<Service><Resource>_<scenario>TestAccVPC_basicTestAccVPC_disappears
数据源验收测试TestAcc<Service><DataSource>DataSource_<scenario>TestAccVPCDataSource_ipv6
列表资源验收测试TestAcc<Service><Resource>_List_<scenario>TestAccVPCPeeringConnection_List_...
单元测试任意不带TestAcc前缀的名字TestFlattenXxx

审查要点:

  • 单元测试严禁调用 AWS。凡是不以TestAcc开头的测试,如果内部发起了 AWS API 调用,审查时必须标记为错误;
  • 服务名使用仓库names包统一管理的大小写风格(如VPCS3RDS),保证跨服务一致。

TestCase 必备四要素

SKILL 给出所有验收测试的统一开头模板:

ctx := acctest.Context(t) acctest.ParallelTest(ctx, t, resource.TestCase{ // ... })

TestCase内必须设置以下四个字段,缺一不可;审查时发现缺失或被替换版本都要标记。

1.PreCheck:三层前置检查

PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionHasService(t, names.<Service>EndpointID) <pkg>_testAccPreCheck(ctx, t) }
  • acctest.PreCheck:位于 internal/acctest/acctest.go,负责校验测试凭证(要求AWS_PROFILEAWS_ACCESS_KEY_ID或容器凭证三者至少其一,且静态密钥必须配AWS_SECRET_ACCESS_KEY),并初始化全局测试 Provider(Provider.Configure),同时把区域默认值写入环境变量,使测试配置可以省略 provider 块。
  • acctest.PreCheckPartitionHasService:位于 internal/acctest/acctest.go,用 AWS 分区端点表检查当前分区是否提供该服务,不提供则直接t.Skipf跳过。
  • testAccPreCheck:服务包自己实现的检查,具体规范见下文「PreCheck 模式」小节。

2.ErrorCheck:服务级错误过滤

ErrorCheck: acctest.ErrorCheck(t, names.<Service>ServiceID)

ErrorCheck 的实现会按服务 ID 查找该服务注册的错误检查函数,并统一过滤「该分区不支持此特性 / 未知操作」之类的公共错误(errorCheckCommon匹配is not supported in thisInvalidActionUnknownOperationExceptionUnsupportedOperation等字符串),命中后自动t.Skipf,让测试在特性未开通的账户/分区上优雅跳过而不是失败。

3.ProtoV5ProviderFactories:Provider 工厂

ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories

该字段通过仓库封装的多区域/多账户工厂族(acctest.go 中的ProtoV5FactoriesNamedProtoV5FactoriesAlternateProtoV5FactoriesAlternateAccountAndAlternateRegionProtoV5FactoriesMultipleRegions等)为测试提供基于 Protocol v5 的 provider 服务器实例。对于跨区域、跨账户等复杂场景,应使用对应的多 Provider 变体而非默认工厂。

4.CheckDestroy:销毁校验

CheckDestroy: testAccCheck<Resource>Destroy(ctx, t)

每个资源测试都要注册自己的 Destroy 检查函数,用于确认测试结束时远端资源确实被清理,防止测试产生遗留资源。

长耗时测试的守卫

对于预计运行超过约 5 分钟的测试,SKILL 要求在acctest.Context(t)之后立刻加入短模式守卫:

if testing.Short() { t.Skip("skipping long-running test in short mode") }

这样 CI 跑go test -short时能快速跳过耗时用例。

随机命名规范

测试中创建的资源名称必须随机,避免硬编码冲突。规范要求统一使用:

sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

其中acctest.ResourcePrefix在 internal/acctest/acctest.go 中定义为"tf-acc-test",因此生成的名称形如tf-acc-test-<随机数>。审查时应标记以下两种情况:

  • 硬编码的名称;
  • 裸用acctest.RandString(...)(不带前缀)。

顺带说明,仓库还在 vcr.go 中提供了 VCR 友好的acctest.RandomWithPrefix变体:当 VCR(测试录制回放)启用时使用确定性随机源,保证回放可复现。

PreCheck 模式:单次调用 + 跳过语义

testAccPreCheck的实现有严格的纪律要求。SKILL 给出的准则是:

  • 只发起一次廉价的 List/Describe 调用
  • 命中分区/权限类错误时通过acctest.PreCheckSkipError(err)判断并t.Skipf跳过;
  • 其他真实错误才t.Fatalf

仓库实际样例见 internal/service/ec2/transitgateway_default_route_table_association_test.go:

func testAccPreCheck(ctx context.Context, t *testing.T) { conn := acctest.ProviderMeta(ctx, t).EC2Client(ctx) input := &ec2.DescribeTransitGatewaysInput{} _, err := conn.DescribeTransitGateways(ctx, input) if acctest.PreCheckSkipError(err) { t.Skipf("skipping acceptance testing: %s", err) } if err != nil { t.Fatalf("unexpected PreCheck error: %s", err) } }

PreCheckSkipError实现在 internal/acctest/acctest.go,它把「分区未开通该 API」类错误统一判为可跳过:包括AccessDeniedException(GovCloud 中端点存在但未启用)、UnknownOperationExceptionUnsupportedOperationInvalidActionForbiddenException、DNS 解析失败等。审查时要标记以下反模式:

  • PreCheck 发起多次 API 调用;
  • 直接return err而不是t.Skipf/t.Fatalf
  • 遗漏PreCheckSkipError判断(导致未开通特性在 CI 上误报失败)。

ImportState 步骤

_basic测试的最后一个步骤必须是导入校验:

{ ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }

其中ImportStateVerify: true表示导入后要与现有状态做一致性比对。对于 AWS API 不返回的只写字段(如密码、apply_immediately这类需要立即生效的参数),应使用ImportStateVerifyIgnore显式声明忽略:

ImportStateVerifyIgnore: []string{"password", "apply_immediately"},

审查要点:如果发现某个测试使用大而全的忽略列表来掩盖真实的漂移(drift)问题,必须标记——忽略列表只能用于真正的只写字段,不能用来掩盖状态不一致的缺陷。

Disappears 测试的两种写法

_disappears测试中「带外删除资源」的辅助函数按资源实现框架分为两种:

  • Terraform Plugin Framework 资源
acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tf<svc>.Resource<Name>, resourceName)
  • Terraform Plugin SDKv2 资源
acctest.CheckSDKResourceDisappears(ctx, acctest.Provider, tf<svc>.Resource<Name>(), resourceName)

(注意 SDKv2 变体传入的是资源构造函数的调用结果,带(),返回*schema.Resource。)

从实现上看,framework.go 中的CheckFrameworkResourceDisappears会为资源构造一个仅含顶层字符串属性的简化 Framework State,然后直接调用该资源的Delete方法完成带外删除;对于依赖嵌套/非字符串参数才能执行删除的资源,SKILL 配套提供了CheckFrameworkResourceDisappearsWithStateFunc,允许通过自定义 state 函数补全删除所需状态。仓库还针对按区域覆盖的资源做了容错处理:若删除时出现 "Value Conversion Error",会向 schema 注入顶层region属性后重试(见 framework.go)。

正则与 ARN 断言规范

必须使用regexache

SKILL 明确要求测试中的正则表达式使用github.com/YakDriver/regexache包,而不是 Go 标准库的regexp。审查时若发现新测试import "regexp",直接标记。仓库中的实际用例(如vpc_test.goregexache.MustCompile(\vpc/vpc-.+`)`)也印证了这一约定。

ARN 断言:使用区域感知的匹配函数

对于 ARN 类属性,规范要求使用仓库提供的区域感知匹配函数,而不是手工拼接:

场景推荐函数
当前区域 ARNacctest.MatchResourceAttrRegionalARN(ctx, resourceName, attr, service, regexp)
指定区域 ARNacctest.MatchResourceAttrRegionalARNRegion(...)
无账号段 ARNacctest.MatchResourceAttrRegionalARNNoAccount(...)
指定账号 ARNacctest.MatchResourceAttrRegionalARNAccountID(...)

这些函数集中定义在 internal/acctest/acctest.go 附近。它们会根据测试当前所在分区与区域自动推导 ARN 前缀与账号段,从而消除测试对硬编码账号/区域的依赖。审查时应标记**用fmt.Sprintf手工拼 ARN(包含账号 ID 或区域)**的做法。

vpc_test.go中的一行是标准用法:

acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "ec2", regexache.MustCompile(`vpc/vpc-.+`))

审查清单速查

结合上文,把 SKILL 的要点浓缩为一份可执行的 PR 审查清单:

  1. 必备测试:新资源是否同时具备_basic(含 ImportState 收尾、全属性断言)与_disappears?带@Tags/ identity 注解的资源是否删除了手写的_tags*/_Identity_*测试(应由生成器生成)?
  2. 命名:验收测试是否遵循TestAcc<Service><Resource>_<scenario>?数据源/列表资源是否用了各自的DataSource_/_List_后缀?单元测试是否误加TestAcc前缀、或出现调用 AWS 的单元测试?
  3. TestCase 四要素PreCheck(三层)、ErrorCheck: acctest.ErrorCheck(t, names.<Service>ServiceID)ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactoriesCheckDestroy是否齐全且未被替换?
  4. 长测试守卫:预计超过约 5 分钟的测试是否在acctest.Context(t)后添加testing.Short()跳过逻辑?
  5. 随机命名:是否使用sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)?有没有硬编码名称或裸acctest.RandString
  6. PreCheck 模式testAccPreCheck是否只做一次廉价 API 调用、是否通过PreCheckSkipError支持跳过?
  7. Import:忽略列表是否只覆盖真正的只写字段?
  8. 正则与 ARN:是否用regexache替代regexp?ARN 断言是否使用区域感知函数而非fmt.Sprintf手工拼接?

延伸阅读

  • 配套技能:review-tests-helpers(Exists/Destroy 检查与数据源、列表资源、单元测试的深入规范)
  • 同族审查技能:review-schema、review-tags、review-identity、review-lifecycle
  • 测试辅助实现:internal/acctest/acctest.go、internal/acctest/context.go、internal/acctest/framework.go、internal/acctest/vcr.go
  • 权威测试范例:internal/service/ec2/vpc_test.go
  • 运行验收测试的环境变量与操作说明:docs/running-and-writing-acceptance-tests.md
  • 单元测试编写指南:docs/unit-tests.md

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 20:50:59

Vue3页面布局溢出排查:横向滚动条、flex与组件库的修复指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 20:48:51

航拍无人机选购指南:核心参数与避障图传深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 20:48:07

Matlab多址接入协议仿真:ALOHA与CSMA吞吐量实现与调试

简介&#xff1a;基于Matlab实现的多址接入协议仿真代码包&#xff0c;面向通信工程、电子信息、计算机等专业学习者&#xff0c;帮助其理解ALOHA、时隙ALOHA及非持续CSMA等经典随机多址接入协议的工作机制与性能差异。压缩包内共6个文件&#xff0c;全部为.m格式源码&#xff…

作者头像 李华
网站建设 2026/9/15 20:47:53

Oracle 11g Linux虚拟机安装全攻略:从环境准备到问题排查

1. 安装前的整体规划与介质准备1.1 为什么到现在还有人在装Oracle 11g看到标题点进来的朋友&#xff0c;估计心里都有同一个疑问&#xff1a;Oracle 12c、19c、21c都出了这么多代&#xff0c;为什么还要折腾11g&#xff1f;说句实在话&#xff0c;我自己在培训环境和项目维护里…

作者头像 李华
网站建设 2026/9/15 20:47:46

EMC节能收益模型:物理-经济-风险三层建模实战指南

1. 这不是财务报表&#xff0c;是EMC项目的生命线&#xff1a;为什么一套模型能决定合同签不签、钱能不能回“EMC效益分享”“节能量保证”“能源托管”——这三个词在节能服务行业里&#xff0c;几乎天天挂在嘴边&#xff0c;但真正敢拍着胸脯说“我算得准”的人&#xff0c;不…

作者头像 李华