Laravel API资源测试:依赖注入下路由参数测试时未实例化
解决Laravel测试中路由模型绑定无法实例化的问题
这个问题我之前在项目里也碰到过,核心原因是测试中使用表单方法伪造(_method=PUT)时,Laravel的路由模型绑定时机和请求方法处理的顺序冲突,导致无法正确解析出User实例。
为什么Postman正常,测试却不行?
当你用Postman直接发送PUT请求时:
- Laravel先匹配到
PUT /api/users/{user}这个路由 - 触发路由模型绑定,自动把URL中的
id转换成User实例 - 最后将实例注入到
UpdateUserRequest和控制器方法中
而在测试中使用json('POST', ..., ['_method' => 'PUT'])时:
- 请求初始方法是POST,Laravel先尝试匹配POST类型的路由(apiResource的POST路由是
/api/users,用于创建资源) - 之后
MethodOverrideMiddleware才会把请求方法修改为PUT,但此时路由已经匹配完成,模型绑定的逻辑没有被触发 - 所以
$this->route("user")只能拿到URL里的字符串ID,而非实例化的User对象
两种解决方案
方案1:直接使用正确的HTTP方法调用
Laravel的测试json方法支持直接指定PUT方法,不需要用POST伪造,这样路由模型绑定会正常工作:
$this->actingAs($this->user) ->json('PUT', '/api/users/'.$this->user->id, [ 'data' => [ // 你的请求参数 ] ]);
或者更简洁的,使用put方法(适用于非JSON格式的请求,也支持传数组参数):
$this->actingAs($this->user) ->put('/api/users/'.$this->user->id, [ 'data' => [ // 你的请求参数 ] ]);
方案2:手动在Request中解析模型(备选方案)
如果你因为某些原因必须使用POST+_method的方式,可以在UpdateUserRequest中手动查找模型:
public function rules() { // 手动从路由参数获取ID并查找模型 $user = User::findOrFail($this->route('user')); // 接下来使用$user做逻辑处理 // ... }
不过这个方案会让你的Request和测试环境耦合,不如方案1优雅,所以优先推荐方案1。
验证效果
修改测试代码后,再次调用dd($this->route("user")),就能看到正确的User实例了,和Postman中的结果一致。
内容的提问来源于stack exchange,提问作者Kirill Simin
相关产品推荐
相关产品推荐

