
本文介绍如何为 Laravel 模型中的本地作用域(如 scopeFilter)编写可靠、可维护的 PHPUnit 单元测试,涵盖数据准备、断言设计及大小写敏感查询的验证要点。
本文介绍如何为 laravel 模型中的本地作用域(如 `scopefilter`)编写可靠、可维护的 phpunit 单元测试,涵盖数据准备、断言设计及大小写敏感查询的验证要点。
在 Laravel 中,模型作用域(Scopes)是封装常用查询逻辑的重要方式,但其行为必须通过测试保障正确性。以 Statistic 模型的 scopeFilter 为例——它根据 search 参数对 country 字段执行不区分大小写的模糊匹配,底层使用 DB::raw('lower(country)') 和 strtolower() 实现兼容性。为全面验证该作用域,推荐创建独立的单元测试类(如 StatisticScopesTest),而非混入 Feature 测试,以提升执行速度与定位精度。
以下是一个结构清晰、覆盖边界场景的测试示例:
<?php namespace Tests\Unit;
use App\Models\Statistic;
use Tests\TestCase;
class StatisticScopesTest extends TestCase
{
/** @test */
public function it_filters_statistics_by_country_case_insensitively()
{
// ✅ 空数据场景:确保作用域在无数据时安全返回空集合
$this->assertSame(0, Statistic::count());
$this->assertSame(0, Statistic::filter(['search' => 'pt'])->count());
// ✅ 创建测试数据(注意大小写变体,验证 case-insensitive 行为)
Statistic::factory()->create(['country' => 'Portugal']);
Statistic::factory()->create(['country' => 'PT']);
Statistic::factory()->create(['country' => 'Brazil']);
// ✅ 正向匹配:搜索 'pt' 应命中 'PT' 和 'Portugal'(因 lower() 转换)
$this->assertSame(2, Statistic::filter(['search' => 'pt'])->count());
// ✅ 大小写无关:'PT'、'pt'、'Pt' 均应等效
$this->assertTrue(Statistic::filter(['search' => 'PT'])->exists());
$this->assertTrue(Statistic::filter(['search' => 'pt'])->exists());
$this->assertTrue(Statistic::filter(['search' => 'Pt'])->exists());
// ✅ 反向验证:搜索不存在的国家(如 'EN')应返回空
$this->assertFalse(Statistic::filter(['search' => 'EN'])->exists());
// ✅ 空搜索参数应被忽略(when() 的 falsey 判定)
$this->assertSame(3, Statistic::filter(['search' => null])->count());
$this->assertSame(3, Statistic::filter(['search' => ''])->count());
}
}
关键实践说明:
- 使用 assertSame() 替代 assertEquals():避免类型隐式转换导致的误判(如 0 == '0' 为 true,但 0 === '0' 为 false);
- 覆盖大小写组合:显式测试 'PT'/'pt'/'Pt',确认 lower() 与 strtolower() 协同生效;
- 验证空值处理:when() 对 null、''、false 等 falsy 值自动跳过,需确保不意外过滤全部数据;
- 避免数据库残留:Laravel 测试默认启用 RefreshDatabase,每次测试后自动重置,无需手动清理;
- 不依赖真实翻译字段:HasTranslations 在测试中若未配置翻译表,可临时禁用或使用 withoutEvents() 避免触发翻译逻辑干扰主流程。
最后,将该测试类置于 tests/Unit 目录下,并通过 php artisan test --filter StatisticScopesTest 快速运行验证。一个健壮的作用域测试,不仅是功能校验,更是未来重构的安全网。











