Laravel单元测试报call to member function call() on null,如何mock FormRequest的validated?
问题原因
直接全量Mock SaveFormRequest 类时,没有初始化Laravel FormRequest 内置依赖的验证器、容器实例,ValidatesWhenResolvedTrait 中的回调调用缺少必要的对象,因此抛出call to a member function call() on null错误。
解决方案
方案1:使用Laravel原生HTTP测试(更推荐)
Laravel官方为表单请求测试提供了原生支持,无需手动Mock请求类,直接通过构造请求数据发送POST请求即可完成测试,同时可以自动触发FormRequest的验证逻辑:
public function test_add_form_logic() { // 构造通过验证的合法请求数据 $validData = [ 'name' => '测试用户', 'phone' => '13xxxxxxxxx' // 补充其他业务要求的字段 ]; // 如果需要Mock服务层避免真实业务操作,可以提前绑定Mock $this->mock(YourServiceLayer::class, function ($mock) use ($validData) { $mock->shouldReceive('addFormDetails') ->once() ->with($validData); }); // 发送POST请求到控制器对应路由 $response = $this->post(route('form.add'), $validData); // 断言响应符合预期 $response->assertRedirect(route('register')); }
方案2:手动Partial Mock FormRequest
如果确实需要直接调用控制器方法而非走HTTP请求,可以使用局部Mock只覆盖validated方法,保留FormRequest的基础初始化逻辑:
public function test_controller_add_form() { // 局部Mock,仅重写validated方法 $saveRequest = $this->partialMock(SaveFormRequest::class, function ($mock) { $mock->shouldReceive('validated') ->once() ->andReturn([ 'mock_field1' => 'value1', 'mock_field2' => 'value2' ]); }); // 实例化控制器并传入Mock请求 $controller = new YourController(); $response = $controller->addForm($saveRequest); // 断言返回结果符合预期 $this->assertEquals(route('register'), $response->getTargetUrl()); }
注意事项
建议单独编写SaveFormRequest的验证规则测试用例,避免在控制器测试中混合验证逻辑的校验,保证测试职责单一。
内容的提问来源于stack exchange,提问作者Balaguru Murugan
相关产品推荐
相关产品推荐

