8.6 KiB
8.6 KiB
Dever 应用测试体系
Goal
让 Dever 应用可以用 Dever 源码编写和运行确定性的领域回归测试,使 AI 修改 App、Domain 或 Model 后能够验证业务合同,而不依赖 Rust 宿主测试、HTTP 接口或正式数据库。
测试是可选能力。没有测试的项目保持现有开发和运行方式;测试能力不得引入第二套解释器、生产可见测试入口或环境变量配置。
Background
- 当前 CLI 只有
check、api、fmt、run和build,应用自身没有测试命令。 - 编译器仓库已有 Rust 回归测试,但它们验证编译器实现,不能表达具体 Dever 应用的业务合同。
- 生产源码从
module/加载,main.main是run/build的唯一启动入口;App 是跨领域能力边界,Domain、Model、Port、Adapter 和 API 是领域实现边界。 - parser、checker、HIR、原生后端、源码位置、错误传播、Model 迁移和 Seed 已有单一正式路径,应由测试复用。
- ORM 的真实 PostgreSQL 验收已经由独立编译器测试覆盖,不属于首版应用测试命令。
Requirements
Source And Discovery
- 应用测试固定放在项目根
test/,与module/生产源码分离。 - 测试路径必须是
test/<component>/<domain>/<topic>.dever或test/<component>/<domain>/<topic>.dever.md,不支持更深层级。 - 每个测试文件由文件名选择同名普通函数作为唯一入口。例如
test/user/account/register.dever执行其中的register() ()。 - 测试入口必须是零输入、零输出的 ordinary 函数。缺少同名函数、同名入口签名错误或重复测试身份必须在执行前产生源码诊断。
- 测试文件中的其他函数和类型只属于该文件,不自动执行,也不能被其他测试文件或生产源码调用。
- 不增加
test关键字、test_前缀、每文件main()、package/expose 声明或顶层可执行语句。 dever test <project-root>同时加载生产源码和测试源码,并在运行任何用例前完成全部语法、名称、类型、分句、effect、失败义务和架构检查。- 发现顺序按测试身份稳定排序,不依赖文件系统遍历顺序。
- 项目没有
test/或目录为空时,合法项目执行dever test输出0 tests并成功退出。 check/api/run/build不加载测试源码。测试声明不进入生产二进制、API 快照或 HTTP 路由。fmt作为源码工具应同时格式化module/和存在的test/,保持两者统一的.dever/.dever.md格式合同;任一源码失败时不得部分改写。
Architecture And Visibility
- 测试文件是所属
<component>/<domain>的测试友元,可以调用同领域 App 和 Domain。 - 跨领域调用只能经过目标 App。
- 测试可以读取 App 返回的 Model 值和同领域类型,但不能直接调用 Model CRUD、Adapter、Port 或 API。
- 生产 App、Domain 和其他测试文件都不能反向调用测试函数或访问测试私有类型。
- 测试不能声明 Model、HTTP 路由或生产 App 能力。
- 测试文件必须表达一个内聚业务场景;不建立
common、shared、utils、helper、全局 fixture 等测试垃圾桶。
Assertions And Failures
- 首版只提供测试源码专用的
assert(condition)和assert_eq(actual, expected)。 assert只接受Bool。assert_eq要求两侧是相同且可比较的类型,不做数值提升、字符串求值或运行时反射。assert_eq复用现有比较与渲染合同,支持标量、record、choice、可空值、List、Map、MapEntry 和 Model ID;失败报告测试身份、源码位置、实际值和期望值。- 不增加
assert_true、assert_false、assert_not_equal、assert_null、异常断言或自定义 matcher。 - 业务失败继续使用现有
result(call)和 choice 分句验证;不增加try/catch/throws。 - 测试成功表示入口正常完成;断言失败、未捕获业务失败或程序 fault 表示该用例失败。
- 一个用例失败后继续运行其余独立用例,最终汇总通过、失败和未运行数量,并以非零状态结束。
Isolation And Lifecycle
- 首版没有
before/after、全局 setup、共享 fixture、用例排序依赖或测试间共享状态。 - 每个测试文件在独立原生进程和独立临时项目目录中运行。
- 不触达 Model 的测试不初始化数据库。
- 触达 Model 的测试由运行器生成每用例独立的临时 SQLite 配置,走正式配置解析、迁移、Seed、事务、连接池和 shutdown 路径。
- 测试运行器不读取、复制或连接项目正式数据库 URL;不使用环境变量或命令行数据库覆盖。
- 临时数据库、数据目录、配置、可执行文件和运行产物在成功或失败后由运行器清理,不写入项目
data/。 - 首版不使用外层事务回滚代替隔离,因为这会改变被测 App 的真实提交和回滚语义。
- 测试按稳定顺序串行运行;并行、随机顺序、重试和自动超时不属于首版。
CLI And Reporting
- 新增正式命令
dever test <project-root>;当前开发二进制对应deverc test <project-root>。 - 默认输出简洁的人类可读状态和最终汇总。测试进程 stdout/stderr 被捕获,不得冒充 runner 状态;失败时按独立区块展示。
- 源码诊断、原生编译失败、进程启动失败、断言失败、业务失败和 runtime fault 保留各自可辨认的信息。
- 测试复用与
run/build相同的原生后端、runtime feature 裁剪、源码位置和构建缓存,不链接 reference evaluator。 - 首版不增加测试名过滤、机器报告格式或新的数据库配置结构。
Maintained Example
- CMS 的 Dever 与 Markdown 项目各自增加等价测试,验证账户规范化、Model 写入/Seed 和文章发布等现有 App 合同。
- 两套测试使用相同路径、入口名称和断言,只因源码容器格式不同而不同。
- 旧
examples/old/不迁移为应用测试模板。
Acceptance Criteria
.dever与.dever.md测试均能按<component>/<domain>/<topic>稳定发现,文件名选择同名零输入、零输出函数。- 非法路径、缺失/错误入口、重复身份、测试跨域越权、直接 Model/API 调用和生产源码反向访问测试均在执行前被拒绝并定位源码。
assert和assert_eq有正反类型检查;相等失败包含测试身份、原源码位置、实际值和期望值。- 测试可以通过
result(call)验证业务失败;未捕获业务失败、断言失败和 runtime fault 均使当前用例失败而不阻止后续用例。 - 无
test/的合法项目执行dever test报告0 tests并成功;非法生产源码仍被拒绝。 - 纯非数据库套件使用 base runtime;混合套件的非数据库用例不读取配置或初始化数据库;使用 Model 的两个测试各自执行迁移和 Seed,写入互不影响,顺序互换结果不变。
- 测试不读取正式
setting.json的数据库 URL,不连接 PostgreSQL,不在项目data/或源码目录留下临时文件。 - 测试进程成功和失败后均清理临时配置、SQLite 文件、可执行文件和 native 临时目录。
check/api/run/build的源码集合、API 快照、CMS 运行结果和生产产物不因存在test/而变化。fmt对 module/test 的变更采用同一次准备后提交;任一格式诊断或准备失败时两处源码均保持原样。- CMS Dever/Markdown 测试覆盖相同业务合同并由
dever test通过。 - 同一项目连续运行两次时测试顺序和汇总一致,生成测试产物不链接 reference evaluator。
- 一次
dever test只生成和编译一个测试套件程序;每个用例仍在独立子进程和临时项目中运行。 - 测试套件复用 native 内容寻址缓存;未改变有效生成代码时再次运行不调用 rustc 编译测试程序。
- 混合数据库/非数据库用例时,只有数据库用例进程读取运行器生成的 SQLite 配置并初始化 Model;非数据库用例不读取配置或初始化数据库。
Out Of Scope
- 真实 PostgreSQL 应用测试配置、schema 管理和外部数据库清理;继续由现有
postgres_orm专项验收负责。 - 自动
before/after、共享 fixture 文件、mock/stub、Port/Adapter 替身和依赖注入协议。 - 测试筛选、watch、并行、随机顺序、重试、自动超时、覆盖率、快照、属性测试和模糊测试。
- 浏览器/UI、HTTP 录制回放、外部服务沙箱和机器可读报告。
- API 新设计、本体、智能体、package registry、跨平台发行和编译器自举。