2. 顶层夹具接口定义
本章定义整套夹具体系的最高层契约——抽象夹具基类。它是所有具象夹具必须遵守的协议,为生命周期管理与数据构建提供类型安全、可测试的骨架。我们围绕边界、分层、职责、数据流/控制流/信任链路、选型权衡、风险点、落地步骤与验收标准展开。
2.1 边界
抽象夹具基类的边界如下:
- 不依赖具体数据库实现(Room、Core Data、文件系统)
- 不包含业务逻辑、UI交互或网络调用
- 只负责定义生命周期钩子与数据构建签名,不提供默认实现(纯抽象)
- 所有夹具实现都必须直接或间接继承此基类
2.2 分层位置
分层说明:抽象夹具基类位于最顶层,下接具体夹具实现层(如 UserFixture、OrderFixture),再下层为数据库操作层(DAO/SQLite)。测试用例只依赖顶层接口,不直接操作具体夹具或 DAO。
2.3 组件职责
| 组件 | 职责 | 抽象方法示例 |
|---|---|---|
| 抽象夹具基类 | 定义契约骨架,提供类型安全,强制子类实现生命周期与数据构建 | abstract class BaseFixture<T> |
| 生命周期方法 | 管理夹具的创建、清理、重置状态,支持 beforeAll/afterAll 等高阶钩子 | abstract fun setup() |
| 数据构建接口 | 返回类型安全的实体实例或集合,允许构造器/工厂模式 | abstract fun build(): T |
2.4 数据流 / 控制流 / 信任链路
- 数据流:测试用例 → 调用数据构建接口 → 夹具返回实体对象 → 注入 DAO → 持久化到数据库 → 测试读取验证。
- 控制流:单元测试框架触发 beforeAll → 夹具 setup() → 测试方法执行 → 夹具 teardown() → afterAll。
- 信任链路:测试框架信任夹具生命周期按序执行;基础夹具信任继承子类正确实现了抽象方法;测试用例信任 build() 返回的实体与数据库架构一致。
2.5 选型权衡
| 方案 | 优点 | 缺点 |
|---|---|---|
| 抽象基类 | 强制契约,支持模板方法模式,可定义非抽象生命周期默认实现 | 单继承限制,Java/Kotlin 类层级复杂时易耦合 |
| 纯接口(interface) | 多继承灵活,与依赖注入配合更自然 | 无法提供默认行为,每位实现需重复样板代码 |
| 函数式(顶层函数 + lambda) | 轻量、零继承开销,适合简单测试 | 无法受益于类型安全检查,复杂场景难以维护 |
推荐:对于中型以上项目,优先使用抽象基类 + 辅助接口(如
LifecycleAware)的组合,平衡强制与灵活。
2.6 风险点
- 生命周期依赖顺序:若子类重写 setup 时未调用 super.setup() 可能导致数据库链接未初始化。
- 数据构建接口过宽:抽象方法签名过于泛化(如返回 Any/Object),失去类型安全。
- 抽象基类膨胀:频繁增加新抽象方法会导致所有现有夹具实现编译失败。
- 重置行为不一致:部分夹具的 reset() 未清理依赖表,造成测试干扰。
2.7 落地步骤
- 定义抽象基类骨架:在 fixture-core 模块中创建
abstract class BaseFixture<T>,声明泛型。 - 声明生命周期抽象方法:
abstract fun setup()、abstract fun teardown()、open fun reset()(可带默认空实现)。 - 声明数据构建抽象方法:
abstract fun build(): T、abstract fun seed(count: Int): List<T>。 - 编写第一组单元测试:创建 FakeFixture 继承基类,验证生命周期调用顺序与 build 返回类型。
2.8 验收标准
| 编号 | 验收条件 |
|---|---|
| 2.1 | 存在一个打包为 fixture-core 的抽象基类模块,不依赖任何 Room 或 Android 库。 |
| 2.2 | 基类至少包含 setup、teardown、reset、build、seed 五个抽象/可覆写方法。 |
| 2.3 | 所有抽象方法返回类型都为泛型 T 或 List<T>,无 Object 返回。 |
| 2.4 | 编写单元测试验证两次调用 setup 不会抛异常(幂等性)。 |
| 2.5 | 重置测试:调用 reset() 后重 build 返回全新实体,引用不相等。 |
关键检查:验收时需确保所有新夹具实现必须继承基类而非直接拷贝接口签名,否则视为架构违规。