Pangolin 统一测试框架 · 架构说明

分层方法论 + 脚手架模板 + 单一编排入口 · 可自动化 / 可量化 / 可自定义

定性(方案 A):不存在一个能同时覆盖「界面渲染 / 交互驱动 / 后端记账 / 真链路端到端」的单一工具——这四者运行时根本不同。所以「一套测试框架」= 一套分层方法论 + 一组可复用脚手架模板(假桥、Provider 覆盖、golden+字体锁、Go 真库套、E2E compose 骨架)+ 一个统一编排入口。跨多端项目的复用方式是模板复制后按接缝适配,而非全项目 import 同一个包。
↔ 配套文档:开发规范 · 可测试性五支柱(「怎么写才好测」——测试能力的前置条件)

设计原则

前不久的「mac 实时统计恒为 0」就是典型反例:原生侧产出统计、Dart 侧消费统计,两端的 pangolin/vpn/stats 契约没有任何自动化测试守门,触发条件一变(隧道已连接才启动 app)就静默失效。L0 契约层防的正是这类 bug。

① 分层测试金字塔

图 1 · 五层金字塔:L0 契约为地基,L1→L4 自底向上

L4 E2E L3 视觉一致性 golden · pixelmatch L2 集成 · 交互 flutter flow · httptest · bufconn · 真库 L1 单元 flutter_test · go test+testify(纯逻辑) L0 契约 / 静态闸 · 地基 契约快照 · OpenAPI 校验 · analyze/vet · 红线词扫描 L4 E2E docker-compose 真链路冒烟 越往上:越真实·越慢·越脆·越少 越往下:越多·越快·越稳·越省

② 契约接缝数据流

统计/记账数据沿一条跨进程链路流动。每段接缝标注其契约,以及哪一层测试在此下刀——这张图就是「该测什么、在哪测」的地图。

图 2 · 契约接缝:从节点数据面一路回到客户端 UI

原生隧道 / libbox sing-box(客户端) Flutter Dart 层 UI / Riverpod Go 控制面 :8080 HTTP + DB agent :9443 gRPC mTLS 节点数据面 sing-box 出网 ① stats EventChannel ② /v1/* HTTP JSON ③ UsageEntry gRPC ④ V2Ray stats L0 契约 + L2 flow VpnBridgeMock L2 httptest ApiClient 注入 L2 bufconn ✓强 自签 CA/CRL L4 真流量 ✗缺 E2E 待建

实时上下行走 ①(libbox→EventChannel→Dart);累计流量/周柱走 ④→③→DB→②(节点统计→agent→控制面入库→客户端拉取)。两条流共用同一张接缝图,测试各自归位。

③ 四类诉求 → 层 → 工具 → 量化指标

把你提出的四类测试诉求逐条落到层、工具、量化指标与现状:

诉求工具量化指标现状
① 界面设计一致
每端一致
L3 Flutter golden(字体锁定,host 无关→天然每端一致);design-distill pixelmatch 对照 HTML 原型真相源 像素不一致比例 vs 阈值 0.05;golden 通过/失败 素材齐 · CI 没跑
② 前端交互
连接 / 登陆 / 登出
L2 flutter_test 进程内驱动整树 + VpnBridgeMock + http MockClient + ProviderScope 覆盖 流程通过/失败;覆盖率 lcov 素材齐 · 待组装
③ 数值型
统计 / 实时速度 / 时延
L1 + L4 L1:格式化/换算纯逻辑单测;L4:连真节点拉 stats 断言 bytes 增长、延迟 >0 实测 vs 期望容差;时延 ms;速率 B/s >0 L1 可补 L4 缺
④ 后端网络
按租户流量 / 限流
L2 + L4 L2:SQLite 真库 + testcontainers MySQL(已覆盖并发/重放/跨日/配额);L4:全链路真流量计数 记账数值断言;限流是否触发;覆盖率 go cover L2 强 L4 缺

④ 逐层详解

L0 · 契约 / 静态闸

守住接缝的「字段形状」

L1 · 单元

纯逻辑,最快最稳

L2 · 集成 / 交互

带假替身的真实路径

L3 · 视觉一致性

每端渲染一致 + 对照设计真相源

L4 · 端到端冒烟

真链路:统计真不真 / 流量真不真

⑤ 编排与 CI 流水线

一个入口按 profile 分流:CI 每 push 只跑快而稳的 fast;视觉与 E2E 按需触发。

图 4 · 单一入口 → 三 profile 泳道

单一入口 make test / test.sh fast L0 + L1 + L2(假桥/真库) 触发:每次 push(nas CI) 产物:通过/失败 + lcov 覆盖率 visual L3 golden + pixelmatch 触发:push 或本地 产物:pixel diff 报告(HTML) e2e L4 真链路冒烟 触发:本地 / 按需(docker±Mac) 产物:数值容差报告

⑥ L4 端到端冒烟拓扑

图 5 · docker-compose 真链路 + 测试驱动器(推荐边界 a)

测试驱动器 ① 登陆 /v1/auth/login ② 发起连接(真凭证) ③ 发真流量(curl/iperf) ④ 拉 /v1/usage ⑤ 断言 bytes↑ / 限流 docker-compose · 一台 Linux runner 控制面 :8080 HTTP + gRPC :9443 SQLite + Redis 记账存储 agent mTLS enroll · 上报 sing-box 数据面出网 回环出口 httpbin/echo ① ② ④ ③ 真流量经数据面出网 → 计数

⑦ 量化指标总表

维度指标工具 / 口径
覆盖率行/分支 %flutter test --coverage + go test -coverprofile → 合并 lcov
视觉不一致像素比例 vs 阈值 0.05pixelmatch(diff.mjs);golden 通过/失败
数值精度实测 vs 期望容差L4 断言 bytes/速率/累计落在容差带内
时延毫秒 msurltest 延迟 >0 且在合理区间
稳定性通过率 / flaky 率多次重跑统计;flaky 用例隔离

⑧ 可复用与可自定义

跨项目模板(复制即用,按接缝微调)

每项目按接缝定制:契约字段、API 路径、compose 服务清单、golden 屏清单、数值容差阈值。

⑨ 落地路线(建议)

动作性价比起点
1L0 契约快照 + 把现有 golden 接进 CI最高(防回归)素材已有,组装即可
2组装 L2 前端 flow 测试(登陆/续登/连接/登出)Mock/覆盖素材全齐
3L4 后端全链路冒烟 (a)中(覆盖"真不真")需新建 compose + 驱动器
4补 L1 数值单测 + L2 HTTP 鉴权测试增量补齐
5(b) desktop 真连 / (c) 真机——本地按需低(贵·脆)需常驻 Mac / 真机

本文档仅为架构说明(设计真相源)。具体落地拆解(契约快照实现、前端 flow 用例、L4 冒烟脚本)走各自实现计划(writing-plans)。