TiDB IntegrationTest 集成测试框架完全指南:执行计划回归、用例录制与调试实战
【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb
导读:
tests/integrationtest2是 TiDB 仓库中新一代集成测试工具目录,它通过「SQL 用例文件 + 期望结果文件」的驱动模型,自动对比 TiDB 执行器与执行计划的输出差异,是开发者在修改优化器、执行器代码后必须运行的回归防线。本文以该目录的 README 为骨架,结合 run-tests.sh 等真实脚本源码,完整讲解命令行参数、工作原理、用例录制(-r)流程以及 VS Code / GoLand 下的调试方法,帮助你快速上手并理解其内部实现。
一、IntegrationTest 是什么
IntegrationTest 是 TiDB 仓库内置的一套集成测试命令行工具,同时也随仓库附带了一批针对 TiDB执行计划(execute plan)逻辑的高价值测试用例。它的核心价值在于:
- 回归检测执行计划:当开发者修改了优化器、统计信息或执行器相关代码后,执行计划的形状(如表连接顺序、算子选择、索引选择)可能发生非预期变化,IntegrationTest 能自动识别这种变化;
- 端到端行为验证:用例直接以真实 SQL 形式存在,覆盖真实客户端连库执行的完整路径,而不仅是单元测试级别的内部函数调用。
测试用例通过run-tests.sh脚本驱动运行。该目录的完整结构如下:
tests/integrationtest2/ ├── README.md # 使用说明(本文主体) ├── run-tests.sh # 测试驱动脚本 ├── config.toml # 测试用 TiDB 配置 ├── download_integration_test_binaries.sh # 第三方组件二进制下载脚本 ├── r/ # 期望结果(result)目录 │ ├── br_integration.result │ ├── dumpling_import_integration.result │ └── ticdc/ │ └── cdc_integration.result └── t/ # SQL 用例(test)目录 ├── br_integration.test ├── dumpling_import_integration.test └── ticdc/ └── cdc_integration.test与旧版 tests/integrationtest 相比,integrationtest2 引入了「真实组件集群」的概念:脚本会拉起 PD、TiKV、TiFlash、TiCDC 等第三方组件(二进制来自 download_integration_test_binaries.sh 下载),并且测试用例按是否依赖 TiCDC 划分为普通用例与t/ticdc/子目录下的 CDC 用例,从而覆盖备份恢复(BR)、数据导入(Dumpling/Import)等跨组件场景。
二、命令行参数详解
run-tests.sh支持通过选项控制测试行为。README 给出的完整用法如下:
Usage: ./run-tests.sh [options] -h: Print this help message. -s <tidb-server-path>: Use tidb-server in <tidb-server-path> for testing. eg. "./run-tests.sh -s ./integrationtest_tidb-server" -b <y|Y|n|N>: "y" or "Y" for building test binaries [default "y" if this option is not specified]. "n" or "N" for not to build. The building of tidb-server will be skiped if "-s <tidb-server-path>" is provided. -r <test-name>|all: Run tests in file "t/<test-name>.test" and record result to file "r/<test-name>.result". "all" for running all tests and record their results. -t <test-name>: Run tests in file "t/<test-name>.test". This option will be ignored if "-r <test-name>" is provided. Run all tests if this option is not provided. -v <vendor-path>: Add <vendor-path> to $GOPATH. -p <portgenerator-path>: Use port generator in <portgenerator-path> for generating port numbers.各参数的作用与使用场景:
| 参数 | 含义 | 典型场景 |
|---|---|---|
-h | 打印帮助信息 | 快速查阅用法 |
-s <path> | 指定已有的 tidb-server 二进制路径,跳过服务端构建 | 复用本地已编译的调试版服务端 |
-b y/Y | 构建测试所需二进制(默认开启) | 首次运行、代码有变更时 |
-b n/N | 跳过构建,仅运行测试 | 二进制已就绪,只想跑用例 |
-r <name>/all | 运行指定(或全部)用例,并把实际输出录制为新的期望结果 | 新增/修改用例后生成 baseline |
-t <name> | 仅运行指定用例,不录制 | 聚焦调试单个用例;若同时给出-r则-t被忽略 |
-v <path> | 将路径加入$GOPATH | 依赖 vendor 的旧构建流程 |
-p <path> | 指定端口生成器 | 自定义端口分配策略 |
从源码看实现细节:当前仓库中的 run-tests.sh 实际通过getopts "t:s:r:b:d:c:i:h"解析参数,其中-v与-p已经不在解析列表中——README 中保留了这两个历史参数说明,但新脚本的端口分配由内置的find_available_port/find_multiple_available_ports函数自动完成(从 2379、20160、4000 等起始端口向后探测空闲端口),不再需要外部端口生成器。这属于 README 与代码演进的细微差异,使用时应以当前脚本实际支持的能力为准。
三、工作原理:test → 执行 → result 的三段式驱动
IntegrationTest 的工作模型非常简洁,README 中一句话概括:
IntegrationTest will read test case in
t/*.test, and execute them in TiDB server withs/*.jsonstat, and compare integration result inr/*.result.
即:
- 读取用例:从
t/*.test文件读取 SQL 用例(一个.test文件对应一个测试用例集); - 执行查询:在 TiDB Server 上执行这些 SQL,并配合
s/*.json中的统计信息(stats)来保证执行计划可复现; - 比对结果:将实际执行输出与
r/*.result中的期望输出逐行比对,任何差异都会导致测试失败。
其中-r参数的作用就是「以本次实际执行为准,重新生成r/*.result(及s/*.json)」,供后续回归比对使用。
3.1 用例文件与结果文件的格式
以仓库中实际存在的 br_integration.test 为例,用例文件就是纯 SQL,并支持以--开头的特殊指令:
# Test BR and AutoIncrement CREATE TABLE t1 (a INT PRIMARY KEY NONCLUSTERED AUTO_INCREMENT, b INT) AUTO_ID_CACHE = 100; INSERT INTO t1 (b) VALUES (1), (2), (3); SHOW TABLE t1 NEXT_ROW_ID; --backup_and_restore t1 AS tt1 SHOW TABLE tt1 NEXT_ROW_ID;这里--backup_and_restore t1 AS tt1是自定义指令,驱动脚本会调用third_bin/br完成一次真实的备份与恢复(恢复为表tt1),随后继续执行后续 SQL。对应的期望结果 br_integration.result 记录每次 SQL 的输出,例如SHOW TABLE ... NEXT_ROW_ID的输出包含DB_NAME / TABLE_NAME / COLUMN_NAME / NEXT_GLOBAL_ROW_ID / ID_TYPE等列,回归比对就是把这些输出逐字节对齐。
3.2 脚本执行主流程(源码级)
阅读 run-tests.sh 可以还原完整执行链路:
- 准备阶段:脚本开头清理并重建
./data(各组件数据目录pd_data、tikv_data、tiflash_data等)与./logs(各组件日志),并通过export TZ="Asia/Shanghai"固定时区保证结果可复现(源码 L26-L65); - 构建阶段:
build_tidb_server回到仓库根目录执行make server、make build_br、make build_dumpling,并以软链接方式把二进制放入third_bin/;build_mysql_tester通过go install github.com/bb7133/mysql-tester/src安装执行用例所用的 mysql 客户端工具(源码 L128-L154); - 集群启动阶段:
start_tidb_cluster依次启动两个完整的 TiDB 集群——上游集群与下游集群(各含 PD + TiKV + TiDB),为 BR 备份恢复、TiCDC 数据同步等跨集群用例提供环境。服务端以-store tikv -path "<pd_client_addr>"连接真实 TiKV,并加载本目录的config.toml(源码 L299-L349); - 用例分发阶段:脚本将
t/下发现的.test文件按路径分类——位于t/ticdc/下的归入ticdc_cases,其余归入non_ticdc_cases;先执行普通用例,若存在 CDC 用例则额外启动 TiCDC server 并创建 changefeed(--sink-uri="mysql://root:@127.0.0.1:<downstream_port>/")后再执行(源码 L382-L410); - 执行与清理:
run_mysql_tester调用 mysql-tester,传入-port(上游端口)、-downstream(下游 DSN)、--check-error=true、--path-dumpling等参数;录制模式下追加--record。脚本通过trap ... EXIT保证任何异常退出时都能清理后台进程(源码 L63、源码 L351-L370)。
3.3 测试专用配置
测试运行的 TiDB 使用 config.toml 而非默认配置,其中几个关键项直接影响测试稳定性与功能覆盖:
lease = "0" host = "127.0.0.1" new_collations_enabled_on_first_bootstrap = true enable-table-lock = true [status] status-host = "127.0.0.1" [performance] stats-lease = "0" [tikv-client.async-commit] safe-window = 0 allowed-clock-drift = 0 [experimental] enable-new-charset = true allow-expression-index = truelease = "0"与stats-lease = "0":关闭 schema 与统计信息相关的租约延迟,让测试会话能立刻看到 DDL 与统计变更,保证用例结果确定;new_collations_enabled_on_first_bootstrap = true:在首次启动即启用新排序规则(new collation),让排序/比较行为可预期;enable-table-lock = true:开启表锁,覆盖 DDL 相关路径;[experimental]段开启新字符集与表达式索引,扩大测试覆盖的语法面。
四、回归执行计划:提交代码前的必备检查
IntegrationTest 最常见的用途是回归检测执行计划变化。当你修改了优化器、统计模块或执行器代码后,在 TiDB 仓库根目录执行:
make dev或仅运行集成测试:
make integrationtestmake dev是完整的开发工作流目标(checklist、integrationtest、单测等串行执行),而make integrationtest专门负责集成测试。从 Makefile 可以看到该目标的实现:
.PHONY: integrationtest integrationtest: ## Run integration tests with coverage integrationtest: server_check @cd tests/integrationtest && GOCOVERDIR=../../$(TEST_COVERAGE_DIR) ./run-tests.sh -s ../../bin/tidb-server它会先做server_check,然后进入集成测试目录,复用../../bin/tidb-server并开启覆盖率采集(GOCOVERDIR)来执行用例。只要某个用例的实际输出与r/*.result不一致,测试即失败,从而暴露出执行计划或结果的意外变化。
需要说明的是:当前 Makefile 中的
integrationtest目标仍指向旧版目录tests/integrationtest,而本文所述的tests/integrationtest2是新一代目录。两者使用方法一致(README 描述的make dev/make integrationtest工作流对二者都适用),新版目录的改进点在于真实多组件集群(PD/TiKV/TiFlash/TiCDC/BR/Dumpling)的支持。如果你需要为 integrationtest2 走 Makefile 流程,可以参照旧目标的写法自行指定目录与二进制。
五、新增用例与录制期望结果(-r 实战)
当你需要新增测试场景时,流程如下:
- 编写用例:在
tests/integrationtest2/t/下新建以.test结尾的文件,或在已有文件的末尾追加新的 SQL 查询; - 录制结果:在
tests/integrationtest2目录下执行(README 原文写的是tests/integrationtest,对应本文目录时请替换):
cd tests/integrationtest2 ./run-tests.sh -r [casename]-r会运行t/<casename>.test并把实际输出录制到r/<casename>.result;若传入-r all则重新录制全部用例结果。录制完成后,r/*.result即成为后续回归比对的 baseline。
源码层面的录制实现:从 run-tests.sh 可以看到,录制模式与非录制模式共享同一执行函数,唯一区别是录制时向 mysql-tester 追加了--record标志;同时脚本会把-r指定的用例名自动透传给-t逻辑,保证只录制目标用例。-r与-t同时出现时,-r优先(-t被忽略),这一行为与 README 的描述一致。
注意事项:
- 新增用例会实际写入(执行 DDL/DML)到测试集群,因此在本地调试、录制时请使用隔离的环境,避免污染开发数据库;
- 依赖统计信息的用例,应同时确认
s/*.json统计信息是否就绪,以保证执行计划的确定性(README 中说明执行时会配合s/*.json加载统计信息;在 integrationtest2 当前目录结构中暂未包含s/目录,可推断统计信息加载机制沿用自旧版 tests/integrationtest 的设计); - 录制结果后应人工 review 一遍
.result文件,确认输出符合预期,再提交作为回归基线。
六、集成测试调试指南
集成测试用例本质上是「向 TiDB Server 发送 SQL 并比对输出」,因此调试思路是:先用调试器拉起一个 TiDB Server,再用任意 MySQL 客户端手工执行用例 SQL,逐条核对输出。
6.1 Visual Studio Code
- 在项目根目录的
.vscode/launch.json中添加如下配置(若需要切换为带 TiKV 的集群,可修改 pkg/config/config.toml.example 中的相关配置):
{ "version": "0.2.0", "configurations": [ { "name": "Debug TiDB With Default Config", "type": "go", "request": "launch", "mode": "auto", "program": "${fileWorkspaceFolder}/cmd/tidb-server", "args": ["--config=${fileWorkspaceFolder}/pkg/config/config.toml.example"] } ] }这里调试入口是 cmd/tidb-server(TiDB Server 主程序),并以仓库示例配置启动。若想调整新排序规则、TiKV 连接等行为,直接修改config.toml.example即可。
- 打开Run and Debug视图(侧边 Activity Bar 中的调试图标,或快捷键F5)启动 TiDB Server;
- 使用任意 MySQL 客户端连接并手工执行集成测试中的 SQL。默认端口为
4000,默认用户root无密码,例如:
mysql --comments --host 127.0.0.1 --port 4000 -u root--comments选项会保留 SQL 中的注释(部分用例依赖注释指令,如--backup_and_restore),建议保留。
6.2 GoLand
可参照 TiDB Dev Guide 中「Run or Debug」章节,在 GoLand 中启动一个带或不带 TiKV 的 TiDB Server(该指南是 TiDB 社区维护的开发者文档),随后同样用任意 MySQL 客户端连接127.0.0.1:4000执行 SQL 即可逐步核对用例输出。
6.3 进阶调试技巧
- 查看执行计划:在 MySQL 客户端中直接执行
EXPLAIN ...,比对r/*.result中的算子树,可快速定位计划形状差异的具体节点; - 查看服务端日志:run-tests.sh 会把各组件日志写入
logs/目录(如logs/tidb.log),手工调试时关注 TiDB 日志中的[EXECUTOR]、慢查询等信息; - 复用已有二进制:用
-s指定自己编译的调试版 tidb-server,配合-b n跳过构建,可显著缩短调试迭代周期。
七、总结
IntegrationTest 是 TiDB 执行计划与执行逻辑回归保障的关键一环,其「t/*.test用例 +r/*.result期望结果 + 脚本驱动对比」的模型简单而高效:
- 日常开发:修改代码后运行
make dev/make integrationtest,让工具自动暴露执行计划变化; - 扩展覆盖:新增
.test用例后用-r录制结果,快速沉淀回归基线; - 定位问题:通过 VS Code / GoLand 拉起调试版 TiDB Server,配合 MySQL 客户端逐条执行用例 SQL,精准复现与排查差异;
- 跨组件场景:integrationtest2 支持真实 PD / TiKV / TiFlash / TiCDC 集群,用例可覆盖 BR 备份恢复、数据导入同步等端到端链路(对应 t/ticdc/cdc_integration.test 等用例)。
如果你想深入了解脚本的集群编排细节,推荐阅读 run-tests.sh 的完整实现;想为集成测试补充组件二进制,可参考 download_integration_test_binaries.sh;想对比新旧两代套件的差异,可对照旧版 tests/integrationtest/README.md。
【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考