在 laravel 单元测试中,应使用 $this->get('/url', ['key' => 'value']) 发起带 get 参数的请求,避免手动拼接 url 或误用 json()/post();需通过 $request->query('key') 断言参数值,并注意编码、空值及中间件影响。

用 call() 发起带 GET 参数的测试请求
在 Laravel 单元测试中,call() 是最直接的方式模拟 HTTP GET 请求并传入查询参数。它底层调用 Illuminate\Foundation\Testing\Concerns\InteractsWithPages::call(),会自动将数组参数拼成 URL 查询字符串,并设置正确的 $_GET 和 Request 对象。
常见错误是手动拼接 URL 字符串(如 /api/users?name=john&age=25),这容易因编码问题导致测试失败;更糟的是误用 json() 或 post() 方法传 GET 参数——它们不会填充 $request->query(),而只影响 $request->input() 或 $request->json()。
- 正确写法:
$response = $this->get('/search', ['q' => 'laravel', 'page' => 2]); - 等价写法(显式调用):
$response = $this->call('GET', '/search', ['q' => 'laravel', 'page' => 2]); - 若路由含参数(如
/{id}),路径部分和查询参数要分开:$this->get('/users/123', ['include' => 'profile'])→ 实际请求为/users/123?include=profile
验证 GET 参数是否被控制器正确接收
Laravel 的 Request 对象对 GET 参数提供多层访问方式:优先用 $request->query('key')(明确限定来源),其次 $request->input('key')(合并 query + request + json),但后者在测试中易掩盖问题——比如 POST 表单里也传了同名字段,就会干扰判断。
在测试断言时,别只检查响应状态码或 JSON 结构,要确认控制器逻辑是否真读到了 GET 值:
- 用
$this->assertEquals('php', $request->query('lang'));直接断言查询参数值 - 若控制器用了
request('sort')全局辅助函数,它等价于request()->input('sort'),仍建议改用request()->query('sort')提高可测性 - 注意空字符串和缺失键的区别:
request()->query('filter', 'all')会返回'all',但request()->query('filter')返回null(非空字符串)
处理中文、特殊字符等 URL 编码场景
测试中传入中文或符号(如 搜索、user@domain.com)时,Laravel 测试方法会自动 URL 编码,但必须确保控制器没重复解码(例如手动调用 urldecode()),否则会导致乱码或匹配失败。
典型坑点:
-
$this->get('/search', ['q' => 'Laravel+Vue'])→ 实际发送?q=Laravel%2BVue,$request->query('q')返回原字符串'Laravel+Vue'(+ 不会被转为空格,因为 PHP 的$_GET已处理) -
$this->get('/search', ['q' => '你好'])→ 发送?q=%E4%BD%A0%E5%A5%BD,$request->query('q')正确返回'你好' - 如果测试失败且疑似编码问题,可在测试中加日志:
var_dump($request->fullUrl());查看实际构造的 URL
与 assertQueryHas() 等扩展断言配合使用
Laravel 自带的测试断言不包含专门校验查询参数的方法,但你可以快速补一个简洁的自定义断言,避免每次重复取 $request->query():
public function assertQueryHas(string $key, $value = null)
{
$query = $this->app['request']->query();
$this->assertArrayHasKey($key, $query);
if ($value !== null) {
$this->assertEquals($value, $query[$key]);
}
}
然后在测试方法里直接用:$this->assertQueryHas('limit', 10);。注意这个断言依赖当前请求上下文,必须在 $this->get() 调用之后、控制器逻辑执行期间(如通过 expectsEvents 或 withoutExceptionHandling() 触发)才能生效;单纯在测试方法开头调用会报错,因为此时请求尚未绑定到应用实例。
真正容易被忽略的是:测试类继承 TestCase 时,默认使用内存数据库和模拟中间件,但如果你禁用了中间件(use WithoutMiddleware;),某些依赖 StartSession 或 VerifyCsrfToken 的查询参数行为可能异常——尽管 GET 请求通常不受 CSRF 影响,但自定义中间件可能意外修改 $_GET。











