ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

terraform-cdk 集成测试指南:test 目录体系、Jest 驱动与 Edge Provider 测试实践

terraform-cdk 集成测试指南:test 目录体系、Jest 驱动与 Edge Provider 测试实践
  • IaC
  • 云原生
  • 开发工具

【免费下载链接】terraform-cdk

Define infrastructure resources using programming constructs and provision them using HashiCorp Terraform

项目地址:https://gitcode.com/gh_mirrors/te/terraform-cdk
点击查看免费下载

导读

本篇文章围绕terraform-cdk仓库中的 test 目录 展开,系统讲解 CDKTF 集成测试(Integration Tests)的组织方式、运行方法与编写规范。你将了解:测试目录如何按目标语言组织、如何用 Jest 运行单个或全部测试、如何针对本地构建产物(dist)执行端到端验证,以及 Edge Provider 测试与跨语言翻译辅助工具的底层机制,从而能够独立为 CDKTF 贡献新的集成测试用例。

集成测试体系概览

test目录承载着cdktf(CDK for Terraform)项目的集成测试,其核心设计是"以真实用户视角模拟 CLI 操作":

  • 每个子目录代表一种目标语言(typescript、python、csharp、go、java),每个测试再嵌套为独立子文件夹,入口统一为test.ts;
  • 测试使用TypeScript + Jest编写,通过TestDriver驱动真实cdktfCLI 完成init、get、synth、diff、deploy等操作,模拟用户的实际使用过程。

从目录清单可以看到语言矩阵已覆盖主流支持语言,例如 typescript 测试组 包含synth-app、edge、providers、iterators、modules、multiple-stacks、watch等 26 个用例目录,python 测试组 也包含asset、cross-stack-references、terraform-functions、testing-matchers等 12 个用例目录。

运行测试:从单用例到全量执行

环境前提

测试假定cdktfCLI 已经安装并位于PATH中,且项目会使用与 CLI 同版本的cdktf模块——这正是cdktf init的行为。换句话说,集成测试验证的是"当前安装的 CLI + 同版本模块"这一组合下的完整用户路径。

运行单个测试

直接通过 Jest 指定入口文件即可,例如:

npx jest --runInBand typescript/synth-app/test.ts

--runInBand让所有测试在同一个进程内串行执行,避免并发导致的临时目录冲突。

运行全部测试

npx jest --runInBand

以 synth-app 测试 为例,该用例在beforeAll中设置TF_VAR_myvar环境变量、创建 TypeScript 项目并执行cdktf synth,随后断言cdktf debug --json的输出、JSON/HCL 合成结果,以及TF_VAR_环境变量不会被透传到合成产物中(安全设计,输出为no-value-found)。

针对 dist 构建产物运行测试

集成测试最重要的场景之一,是验证"打包发布后的产物"能否正常工作。仓库提供了一整套流程:

$ yarn install $ yarn build $ yarn run package # creates "dist/" $ cd test $ yarn edge:install $ ./run-against-dist npx jest --runInBand

其中yarn run package会生成包含js、python、java、dotnet、go五个子目录的dist/(在 run-against-dist 中会校验这一点,缺少任一子目录即报错退出)。

run-against-dist 的底层逻辑

run-against-dist 脚本完成了几件关键工作:

  1. 通过 local-registry.sh 启动本地 Verdaccio NPM 注册表(默认localhost:4873),并把dist/js下的所有.tgz包npm publish --force上去;
  2. 在临时目录中以--global-style安装cdktf-cli,从而得到一个独立的 CLI 安装点,避免 Node.js 自动把node_modules/.bin注入 PATH 而"遮蔽"待测 CLI(test-helper.ts 注释中说明了这一设计,用以捕获诸如 CLI 通过 NPM 安装后相对路径失效的回归问题);
  3. 将 CLI 路径导出为TEST_PATH_CDKTF_CLI并前置到PATH,随后执行传入的命令(如npx jest --runInBand);
  4. 在退出时通过trap恢复原始 NPM/Yarn 注册表地址并停止 Verdaccio。

安装完成后脚本还会打印cdktf --version,便于确认实际被测的 CLI 版本。

TestDriver:驱动 CLI 的核心测试工具

test/test-helper.ts 提供了集成测试的公共基础设施,其中最重要的是TestDriver类,封装了几乎全部 CLI 操作:

方法对应 CLI 行为说明
init(template, additionalOptions)cdktf init以指定模板初始化项目,默认附加--local --enable-crash-reporting=false等参数
get()cdktf get生成 Provider 绑定(生成到.gen)
synth(flags)cdktf synth合成 Terraform 配置
list(flags)cdktf list列出 Stack
diff(stackName, flags)cdktf diff对比部署差异
deploy(stackNames, outputsFilePath)cdktf deploy部署,默认--auto-approve,可指定--outputs-file
output(...)cdktf output读取输出,支持--outputs-file-include-sensitive-outputs
destroy(stackNames)cdktf destroy销毁资源,默认--auto-approve
watch()cdktf watch监听变更并自动部署(使用 node-pty 模拟 TTY)
validate(stack, baseDirectory)terraform init+terraform validate在cdktf.out/stacks/<stack>下验证生成的配置

辅助能力同样丰富:

  • switchToTempDir():在系统临时目录下创建随机工作目录(/tmp/xxxx/test模式),每个测试在此独立执行,互不干扰;
  • copyFiles / copyFile / copyFolders:把测试目录内的辅助文件(如main.ts、cdktf.json)复制进临时工作目录;
  • setupTypescriptProject / setupPythonProject / setupCsharpProject / setupJavaProject / setupGoProject:按语言一键搭建项目,例如 C# 项目会自动执行dotnet add reference .gen/Providers.Null/Providers.Null.csproj,Go 项目会执行go mod tidy拉取 jsii-runtime;
  • synthesizedStack(stackName)/synthesizedStackContentsRaw(stackName):读取合成产物(cdk.tf.json或 HCL 的cdk.tf),前者返回QueryableStack便于断言;
  • QueryableStack:提供byId(id)(按构造 ID 查找资源/数据源)、output(id)、toString()等查询方法,例如 edge 测试 中大量使用stack.byId("plain").str断言合成结果中的"${optional_attribute_resource.test.str}"引用。

test-helper.ts还导出了一系列按平台/输出模式过滤的测试包装器:onWindows、onPosix、onlyHcl、onlyJson等(通过SYNTH_HCL_OUTPUT环境变量控制),以及sanitizeTimestamps(把日志中的时间戳替换为[<TIMESTAMP>],保证快照测试稳定)。这解释了为什么同一套测试可以同时覆盖 JSON 与 HCL 两种合成输出格式。

编写新测试的规范

新增集成测试遵循三个步骤:

  1. 在目标语言的目录下创建新的子目录;
  2. 在其中创建test.ts文件;
  3. 参照既有用例,用TestDriver组装流程。

编写时需严格遵守以下环境约束:

  • 测试脚本运行在临时工作目录(/tmp/xxxx/test,xxxx为随机目录名)中,不要在测试里写死工作目录;
  • 测试必须假定cdktfCLI 与项目依赖已经可用,禁止在测试内部安装任何依赖或 CLI;
  • 如需通过包管理器安装依赖(如yarn、npm、pipenv、mvn、nuget),这些程序会被"垫片(shim)"处理,以确保消费本地依赖而非远端版本——这正是run-against-dist启动本地 Verdaccio 注册表的原因。

可参考 synth-app、providers(覆盖命名空间、引用、属性变更等 Provider 功能断言)、init-remote-template(验证远程模板初始化及非法 URL 报错)等现有用例来组织辅助文件。

Edge Provider 测试:不构建全部 Provider 也能覆盖边界情况

为什么需要 Edge Provider

如果每个边界场景都要依赖真实云 Provider(AWS、GCP、Azure 等)的完整绑定,测试成本将不可接受。因此仓库构建了一个edge provider,把 Provider Schema 中的各类边界情况集中在一起,专用于覆盖这些用例。

Edge Provider 的生成与快照测试

Edge Provider 的 Schema 定义位于 packages/@cdktf/provider-generator/lib/tests/edge-provider-schema,其测试通过generateProviderBindingsFromSchema在临时目录中生成绑定,并将生成的每个.ts文件与快照(edge-provider-schema.test.ts.snap)比对,从而保证 Provider 生成器输出的稳定性。

构建时,Schema 会被生成到packages/@cdktf/provider-generator/edge-provider-bindings,再通过 GitHub Actions 或edge:install命令复制到测试环境。test/package.json中定义的脚本如下:

{ "edge:install": "rm -rf ./edge-provider-bindings && cp -R ../packages/@cdktf/provider-generator/edge-provider-bindings/ ./edge-provider-bindings", "edge:translateTests": "node ./translate-edge-tests.js", "edge:update": "./run-against-dist ./update-edge.sh" }

edge 集成测试 会把edge-provider-bindings/providers/edge复制到.gen/providers/edge,随后执行cdktf synth并断言各种引用与迭代语义,例如:

  • 列表/集合/映射中普通值的渲染;
  • 对单元素列表、多元素列表、映射的引用展开(如"${list_block_resource.list.singlereq[0].reqbool}"与"${element(list_block_resource.list.req, 0).reqnum}");
  • TerraformIterator生成的for_each与dynamic块(如"${toset(list_block_resource.list.req)}"与each.value.reqstr);
  • 通过Token.nullValue()传递null属性等。

对应的测试入口 edge/main.ts 定义了ReferenceStack、ProviderStack、IteratorStack三个 Stack,覆盖了"资源属性互相引用""引用 Provider 输入(Terraform 原生不支持,CDKTF 支持)""复杂列表/映射迭代"等场景。

跨语言翻译辅助:edge:translateTests

由于边缘用例需要覆盖所有支持语言,仓库用 jsii-rosetta 编写了翻译工具 translate-edge-tests.js:读取 TypeScript 版edge/main.ts,翻译为 Python、Java、C#、Go 四个目标语言文件(translated.py、Translated.java、Translated.cs、translated.go)。文档明确指出:翻译并非完美,只是良好的起点,各语言测试仍需人工校对后完善。

更新 Edge 快照

当 Provider 生成器或 Schema 发生变化时,可通过./run-against-dist ./update-edge.sh触发 update-edge.sh,它对所有语言的 edge 测试执行npx jest -u更新快照。

Provider 生成测试矩阵

test/provider-tests 以 providers.json 定义 Provider 生成测试矩阵(覆盖aws、google、azurerm、kubernetes、consul、vault、oci、datadog、awscc等)。只有当 provider-generator 有变更或设置了ci/test-provider-generation标签时才会运行。

generate-provider-test.js 会根据 Provider 名从template复制出测试骨架,替换main.ts中的导入占位符,并把providers.json中映射的 Provider 源追加到cdktf.json的terraformProviders中;随后 test-provider.sh 通过run-against-dist执行对应快照测试,设置UPDATE_SNAPSHOTS环境变量时则以-u模式更新快照。

其他辅助设施

  • 远程模板测试:template-server.ts 在测试内启动一个本地 HTTP 服务,将packages/@cdktf/cli-core/templates/typescript目录实时打包为template.zip供cdktf init拉取,用于验证从远程 URL 初始化项目的能力。
  • provider 命令测试:typescript/provider-add-command、provider-list-command、provider-upgrade-command等用例分别验证cdktf provider add / list / upgrade系列命令的行为。
  • 断言匹配器测试:typescript/testing-matchers 在项目中复制__tests__后执行yarn test,验证cdktf提供的测试断言库(Testing相关匹配器)能通过"2 passed, 2 total"的期望结果。

小结

test目录是 CDKTF 质量的守门员:它以"真实 CLI 用户"的视角,覆盖 TypeScript/Python/C#/Java/Go 五种语言的完整生命周期操作;通过run-against-dist与本地 Verdaccio 注册表,保证打包产物在接近真实的安装环境下得到验证;借助 Edge Provider 与快照测试,在不构建全部云 Provider 的前提下覆盖引用、迭代、HCL 输出等边界语义。理解这套体系后,无论是定位 CLI 回归、验证新命令行为,还是为某个语言补充端到端用例,都可以沿着"建目录 → 写test.ts→ 用TestDriver驱动 → 对 dist 跑全量"的路径快速上手。

  • IaC
  • 云原生
  • 开发工具

【免费下载链接】terraform-cdk

Define infrastructure resources using programming constructs and provision them using HashiCorp Terraform

项目地址:https://gitcode.com/gh_mirrors/te/terraform-cdk
点击查看免费下载
上一篇:5分钟快速搭建Next.js与FastAPI全栈应用:终极实战指南与最佳方案 🚀
下一篇:Sketch 状态图片处理:加载中、错误、占位符状态完美实现

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进