验证Yii模型查询逻辑需通过UnitTestCase加载fixture、测试find/findOne、where链式查询、with关联预加载及自定义scope,确保条件正确、关联加载、作用域生效,避免脏数据或漏查。

验证 Yii 模型的查询逻辑是否返回预期数据,避免因条件拼写错误、关联关系未加载、作用域未生效等问题导致线上查不到记录或查出脏数据。
准备测试环境与基类
在 tests/unit 目录下创建 UnitTestCase.php,继承 Codeception\Test\Unit 并启用数据库事务回滚机制。
编辑 tests/unit/UnitTestCase.php:用 【$this->haveFixtures(['user'])】 加载 fixture 数据,确保每次测试前数据库状态干净;fixture 文件需放在 tests/_data/user.php 中,且 tableName() 必须返回 'user'(不带表前缀)。
这一步操作起来很简单,直接把文件拖进去就行。
测试 find() 与 findOne() 基础查询
方法一:验证单条记录存在性
在 UserTest.php 中写 testFindOneById():调用 User::findOne(1),断言返回对象实例,并检查 username 是否等于 'admin'。
注意:若数据库中 id=1 的用户被误删或 fixture 未加载,测试会失败——此时不是代码问题,而是测试环境配置缺失。
方法二:验证空结果处理
调用 User::findOne(['id' => 999999]),断言结果为 null。不能用 assertNull() 粗暴判断,必须确认它确实没返回任何模型实例,否则可能掩盖 find() 内部异常抛出但被静默吞掉的问题。
测试 where 条件链式查询
第一步:构造基础查询并验证 SQL 生成逻辑
执行 $query = User::find()->where(['status' => 1])->andWhere(['like', 'username', 'adm']);
第二步:检查生成的 WHERE 条件是否符合预期
用 $sql = $query->createCommand()->getRawSql(); 断言字符串中包含 AND `status` = 1 和 AND `username` LIKE '%adm%' ——【不要依赖 execute() 结果反推条件是否正确,SQL 生成错误可能被数据库兼容性掩盖】。
第三步:执行查询并验证数据量
调用 $users = $query->all(); 断言 count($users) === 1,且 $users[0]->username === 'admin'。
测试 with() 关联预加载
写 testFindWithProfile():User::find()->with('profile')->where(['id' => 1])->one()。
断言返回对象不为 null,且 $user->profile 不为 null,再断言 $user->profile->bio === 'Yii dev'。
关键点:若忘记在 User 模型中定义 getProfile() 关联方法,或 profile 表 fixture 未提供 id=1 的记录,$user->profile 会是空对象而非 null,导致断言失败但报错信息模糊——此时应先确认关联定义和 fixture 数据完整性。
测试自定义 scope 查询
在 User 模型中定义 public function active() { return $this->andWhere(['status' => self::STATUS_ACTIVE]); }
测试时调用 User::find()->active()->all(),断言结果数组长度大于 0。
注意:scope 方法名必须是小写字母开头,且不能与现有属性同名,否则调用时会被当成属性访问而静默失败。


















