- IaC
- 云原生
- 开发工具
【免费下载链接】terraform-cdk
Define infrastructure resources using programming constructs and provision them using HashiCorp Terraform
导读
本篇文章围绕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 脚本完成了几件关键工作:
- 通过 local-registry.sh 启动本地 Verdaccio NPM 注册表(默认
localhost:4873),并把dist/js下的所有.tgz包npm publish --force上去; - 在临时目录中以
--global-style安装cdktf-cli,从而得到一个独立的 CLI 安装点,避免 Node.js 自动把node_modules/.bin注入 PATH 而"遮蔽"待测 CLI(test-helper.ts 注释中说明了这一设计,用以捕获诸如 CLI 通过 NPM 安装后相对路径失效的回归问题); - 将 CLI 路径导出为
TEST_PATH_CDKTF_CLI并前置到PATH,随后执行传入的命令(如npx jest --runInBand); - 在退出时通过
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 两种合成输出格式。
编写新测试的规范
新增集成测试遵循三个步骤:
- 在目标语言的目录下创建新的子目录;
- 在其中创建
test.ts文件; - 参照既有用例,用
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
相关推荐
Positron Notebook功能详解:从基础操作到高级技巧
Positron Notebook功能详解:从基础操作到高级技巧 Positron作为新一代数据科学IDE,其Notebook功能为数据科学家和开发者提供了强大
开发工具代码编辑器数据科学Spectrum 测试体系完全指南:Jest 单元测试与 Cypress 集成测试实战
Spectrum 测试体系完全指南:Jest 单元测试与 Cypress 集成测试实战 本文围绕 Spectrum 开源社区平台的测试体系展开,系统讲解其基于
后端前端即时通讯社交Terraform AWS Provider与Atlantis集成:PR自动化测试
Terraform AWS Provider与Atlantis集成:PR自动化测试 痛点与解决方案 你是否还在为Terraform AWS Provider的P
IaC云原生基础设施
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考