FlowCheck 项目全景|一次接口回归怎样从配置走到报告
本文依据 FlowCheck 的源码和本地验证记录整理,写作使用了 AI 辅助。
创建文章的接口返回了 201,查询接口也返回了 200,读出来的标题却和写进去的不一样。要在下一次改代码后重新检查这件事,还得登录取令牌、创建文章、记下文章 ID、查询核对,再删除测试数据。这些请求单独调通之后,整条业务流程仍值得重复验证。
我做的 FlowCheck 是一个面向个人开发者的 HTTP 接口回归测试平台。它把请求顺序、检查规则和跨步骤传递的变量保存为用例。每次改完代码,可以选一个环境重新跑同一套用例,看看哪一步失败、当时的响应是什么、实际值和期望值差在哪里。当前项目处于早期开发阶段,已经用内置的文章服务验证了从配置、真实发请求到保存报告的链路。
整体架构
浏览器经 Nginx 访问页面和 API。FastAPI 接受配置与运行请求,先把任务写进 PostgreSQL。独立的 Dispatcher 读出待派发任务,通过 Redis 把运行 ID 交给 Celery Worker。Worker 请求被测服务,把步骤结果和进度事件存回 PostgreSQL。浏览器从 API 读取报告和事件。

| 组件 | 用了什么 | 在 FlowCheck 里做什么 |
|---|---|---|
| Web | Vue 3、TypeScript、Vite、Element Plus、Nginx | Vue 负责用例编辑器、运行列表和报告页,TypeScript 约束接口数据结构,Vite 构建前端,Element Plus 提供表单和表格。Nginx 提供构建后的页面,把 /api/ 请求转发到后端,并对 SSE 路径关闭缓冲,让事件可以及时到达浏览器。 |
| API | FastAPI、Uvicorn、Pydantic、SQLAlchemy、asyncpg | FastAPI 提供登录、项目配置、任务提交、报告和事件接口,由 Uvicorn 运行。Pydantic 校验传入的数据,SQLAlchemy 管理数据库模型和事务,API 通过异步驱动 asyncpg 访问 PostgreSQL。 |
| 数据库迁移 | Alembic | 按版本创建和更新平台的数据库结构。Compose 启动时先完成迁移,再启动 API、Worker 和 Dispatcher。 |
| 派发进程 | Python、SQLAlchemy、psycopg | Dispatcher 定期读取数据库里的待派发记录,把运行 ID 发到 Redis。它也会检查长时间没有被领取或没有结束的运行,并更新状态。 |
| 后台执行 | Celery、HTTPX、SQLAlchemy、psycopg | Celery Worker 领取任务,读出快照,用 HTTPX 按顺序请求被测服务,再把检查结果写回数据库。执行放在后台后,提交接口可以先把运行 ID 返回给浏览器。 |
| 平台数据库 | PostgreSQL | 保存用户、项目、接口定义、环境和用例,也保存运行快照、步骤结果、进度事件和待派发记录。历史报告从这里读取。 |
| 消息与缓存 | Redis | 在执行链路中充当 Celery 的消息中转站,暂存待执行的任务。项目概览也用 Redis 做短期缓存,统计数据来自 PostgreSQL。 |
| 被测服务 | FastAPI、SQLite | 文章 Demo API 提供登录、创建、查询和删除接口,作为 Worker 的真实 HTTP 请求目标。它用独立的 SQLite 库存放演示文章。 |
本地使用 Docker Compose 管理这些服务。Compose 把容器连在同一个网络里,配置启动依赖和持久化数据卷,并把 Web、API 文档和 Demo API 的入口映射到本机。用例执行过程和报告读取都可以用这套本地环境演示。
从项目配置到五步用例
在 FlowCheck 里,环境回答「向哪里发请求,用什么配置」,用例回答「按什么顺序发请求,怎样算通过」,运行是选定一个环境执行一次用例所产生的记录。项目把这些配置和历史结果归在一起。
-
登录并创建项目。 注册或登录 FlowCheck 后,在「我的项目」中新建项目。平台按项目所有者校验资源访问权限。FlowCheck 的登录账号用于管理项目,五步用例里的登录请求则使用 Demo API 的账号。
-
配置测试环境。 在「环境配置」中选择部署允许的目标地址,再填写环境变量和公共请求头。以文章 Demo 为例,环境可以提供登录步骤所需的账号和密码。敏感值加密保存,编辑页面回读时只显示是否已设置。
-
按需导入接口定义。 可以在「接口定义」中上传 OpenAPI 3.0 或 3.1 的 JSON 文件。OpenAPI 文件描述接口的方法、路径和参数等信息。选中导入的定义可以预填步骤里的请求字段,实际业务值、鉴权和检查规则仍由编写用例的人确定。也可以直接手动添加步骤。
-
编排用例。 在「测试用例」中新建用例,按业务顺序添加 HTTP 请求。每一步都有一条状态码断言,还可检查 JSON 字段值或响应耗时是否符合预期。需要跨步骤传值时,可以用提取器从响应中读取字段并命名,后面的步骤通过
{{变量名}}引用。 -
提交运行。 在「运行记录」点击「执行用例」,选择用例和环境。提交成功后进入运行报告页,查看运行进度和最终结果。
仓库预置了「文章回归五步」,用来演示两个值怎样在请求之间传递。
| 顺序 | 请求 | 检查与变量传递 |
|---|---|---|
| 1. 登录 | POST /auth/login |
检查 200,从 $.access_token 提取 auth_token,并标记为敏感值。 |
| 2. 创建文章 | POST /articles |
携带 Bearer {{auth_token}},用 smoke-{{run_id}} 作为标题。检查 201,从响应提取 article_id。 |
| 3. 查询文章 | GET /articles/{id} |
用 {{article_id}} 查询同一篇文章,检查 200,并核对 $.title 是否等于创建时使用的标题。 |
| 4. 删除文章 | DELETE /articles/{id} |
删除这次运行创建的文章,检查 204。 |
| 5. 再次查询 | GET /articles/{id} |
再查同一个 ID,预期返回 404。 |
第 5 步的 404 是通过条件,因为这一步验证的是文章已被删除。第 3 步则同时检查状态码和标题,所以返回 200 仍可能触发断言失败。
点下执行之后,后台怎样处理这次运行
1. 冻结输入并创建运行记录
前端向 POST /api/v1/projects/{project_id}/runs 提交用例 ID、环境 ID,并携带一个 Idempotency-Key。同一项目内,用同一个键重试相同的用例和环境 ID 会返回已有运行;用同一个键提交另一组参数会收到 409。主动再执行一次会使用新的键。
API 检查项目归属,读取当前的用例和环境版本,把目标地址、环境变量、公共请求头、步骤定义和执行限制打包成一份加密的运行快照。这次运行固定使用提交时的输入,之后对用例或环境的编辑会在下一次新运行中生效。
接着,API 在一个 PostgreSQL 事务里写入四类记录。
| 记录 | 初始内容 |
|---|---|
| 运行 | 运行 ID、用例与环境版本、加密快照,状态为 queued |
| 步骤结果 | 按顺序预建每一步的记录,状态为 pending |
| 进度事件 | 写入第一条 run.queued |
| Outbox | 记下一条待派发任务,状态为 pending |
数据库提交成功后,API 返回 202 Accepted 和运行 ID。此时浏览器就可以打开报告页,查看这次运行的排队状态。
2. 派发任务并由 Worker 领取
Outbox 可以理解为数据库里的待发清单。创建运行和登记待发任务属于同一个事务,因此即使 API 提交后 Redis 暂时不可用,数据库里仍然有记录可供 Dispatcher 继续处理。
Dispatcher 找到可以发送的记录后,通过 Redis 投递携带 run_id 的 Celery 任务。若投递失败,它会保留待发记录并延迟下一次尝试。若同一条消息被重复投递,Worker 通过 PostgreSQL 的一次条件更新争抢执行权。只有仍处于 queued 且未过排队期限的运行,才能被其中一个 Worker 切换到 running 并领取。
3. 逐步执行请求,保存脱敏结果
Worker 根据运行 ID 取得快照,解密后为这次运行建立独立的变量上下文。以第 2 步创建文章为例,它把第 1 步提取的令牌填入请求头,把本次运行 ID 填入文章标题,再向 Demo API 发送请求。
收到响应后,Worker 检查断言并读取配置了提取规则的字段。只有步骤通过,提取值才会交给后续步骤使用。创建步骤通过后,article_id 就能用于查询和删除。请求的目标受允许列表约束,执行器也对请求超时和响应大小设有限制。
每一步的状态、耗时、脱敏的请求和响应摘要、断言结果与提取结果写入 PostgreSQL,同时记录对应的进度事件。报告中可以看出令牌已被提取,具体令牌值会被遮蔽。遇到失败时,本次运行结束,尚未执行的步骤标为 skipped。
4. 通过事件追踪进度,再读取最终报告
报告页先读取已有的运行记录。运行仍在进行时,页面通过 SSE(Server-Sent Events)接收服务器发送的进度事件,例如开始运行、开始某一步、完成某一步。API 从 PostgreSQL 按事件 ID 读取,连接中断后,浏览器可以带着最后收到的 ID 接着读。多次连接失败时,页面改为定期查询报告。
收到 run.finished 后,页面请求最终报告。进度事件负责告诉页面发生了什么变化,完整的步骤结果和脱敏预览则由报告接口读取。刷新报告或回看历史时,页面读取的是已有运行记录。
运行提交代码 · 任务派发代码 · 用例执行器 · 事件流代码
失败时能看到什么
| 情况 | 运行结果 | 接下来发生什么 |
|---|---|---|
| 五步都满足断言 | passed |
报告保留五步的检查结果。 |
查询返回 200,标题检查失败 |
failed |
报告指出第 3 步的标题断言失败,第 4、5 步被跳过。 |
| 变量未定义、请求发生网络错误或提取失败 | error |
报告记录具体错误和所在步骤,后续步骤跳过。 |
| 排队超时仍无人领取 | error |
派发进程结束这次运行,并记录派发超时。 |
| 执行超时或 Worker 中途退出 | interrupted |
报告提示部分写操作可能已生效,用户可先检查目标服务中的数据。 |
下面这份报告来自一个故意改错标题期望值的演示。查询的状态码断言通过,标题断言失败。此时创建文章已经成功,删除步骤没有执行,测试文章可能留在 Demo 数据库里。Outbox 的重试只负责投递任务;对已经开始的业务 HTTP 请求,FlowCheck 不会自动重放。

在本地跑一遍
准备 Python 3.12 和 Docker Compose v2。先克隆 FlowCheck,再在仓库根目录生成环境文件并启动服务。已有本地 .env 的话,从 Compose 命令开始。
git clone https://github.com/xyyyyi-x/flowcheck.git
cd flowcheck
python scripts/init_env.py
docker compose up --build -d
docker compose ps
等服务启动并通过健康检查后,准备演示数据并提交一次运行。
python scripts/seed_demo.py
python scripts/smoke.py
正常情况下,smoke 会打印 run_status=passed 和五步的状态。也可以打开 http://127.0.0.1:8080,使用本地 .env 中的 PLATFORM_DEMO_USERNAME 和 PLATFORM_DEMO_PASSWORD 登录。进入「文章回归 Demo」,在「运行记录」里选择「Compose Demo」环境和「文章回归五步」用例,从报告中查看每个步骤的结果。

浙公网安备 33010602011771号