自动化测试应聚焦数据库交互关键路径,包括sql正确性、事务行为、数据一致性及dao/orm操作验证;采用sqlite内存库、docker临时实例或文件级隔离确保环境轻量可重置;通过php数组定义fixture、setup/teardown控制数据状态;断言关注业务行为而非sql实现;ci中独立运行、禁用xdebug、并行执行且保障隔离。

明确测试目标与范围
自动化测试不是为覆盖所有代码而存在,而是聚焦在数据库交互的关键路径上。重点包括:SQL 查询的正确性(如 WHERE 条件、JOIN 逻辑)、事务行为(提交/回滚是否符合预期)、数据一致性(如外键约束、唯一索引是否生效)、以及 DAO 层或 ORM 操作(如 insert、update、delete、find)的返回结果与副作用是否符合设计。
选择轻量可重置的测试数据库环境
避免使用开发或共享数据库,推荐采用以下方式之一:
- 内存数据库:SQLite 最适合 PHP 单元测试,无需安装服务,通过 PDO 连接即可,每次测试前可快速重建 schema;
- Docker 临时实例:用 MySQL 或 PostgreSQL 官方镜像启动容器,测试前初始化并导入最小 schema,测试后销毁容器;
-
文件级隔离:若必须用 MySQL,可为每个测试类分配独立数据库名(如
test_user_service_12345),测试结束执行DROP DATABASE。
构建可重复的数据准备与清理机制
测试稳定性依赖于干净、可控的初始状态。不依赖手动 SQL 文件或全局 fixture:
- 用 PHP 数组定义测试数据模板,通过封装的
insertFixture()方法批量写入,自动处理主从关系和时间字段; - 在 PHPUnit 的
setUp()中创建表结构(或调用迁移命令),tearDown()中清空表(TRUNCATE)或删除数据库; - 对涉及事务的测试,显式开启事务并在
tearDown()中回滚,避免污染后续用例(注意 PDO 默认 auto-commit,需手动$pdo->beginTransaction())。
编写断言时关注“行为”而非“实现细节”
测试应验证业务效果,而非 SQL 字符串或内部变量。例如:
立即学习“PHP免费学习笔记(深入)”;
- 不要断言
$sql === "SELECT * FROM users WHERE status = ?"; - 应断言
$users = $userRepo->findActive(); $this->assertCount(2, $users); $this->assertEquals('active', $users[0]->status);; - 对写操作,查库确认结果:
$this->assertDatabaseHas('orders', ['user_id' => 101, 'status' => 'paid']);(可基于 Laravel 的assertDatabaseHas思路自行封装)。
集成到 CI 并控制资源开销
数据库测试比纯逻辑测试慢,需合理管理执行效率:
- 将数据库测试归入独立的 PHPUnit 测试套件(如
tests/Database),CI 中单独运行,不与单元测试混跑; - 禁用 Xdebug 或降低覆盖率采集粒度(如只统计 src/ 不含 tests/);
- 启用并行执行(如 via
paratest),但确保各测试用例间无数据库共享或竞争(靠独立 DB 或事务隔离实现)。










