Laravel 9单元测试报错:Call to a member function validated() on null
问题
我正在为某控制器方法编写测试,该方法会验证请求数据并通过第三方API创建文档,之后返回状态码201的响应。我用Mock模拟了负责创建文档的DocumentService类,但运行测试时抛出错误:Call to a member function validated() on null,错误出现在控制器的$data = $request->validated();行。明明通过dump($request)能看到它是包含所有必填字段的对象,却无法调用validated()方法。
控制器代码:
public function margin(MarginRequest $request){ $data = $request->validated(); $fileId = $this->documentService->createDocument(auth()->user()->id, SignableDocumentAbstract::MARGIN_CERTIFICATE, new MarginDocument(), $data); return response()->json([ 'code' => 201, 'message' => 'Margin agreement generated successfully', 'data' => [ 'uuid' => $fileId ] ], 201); }
测试代码:
public function test_public_margin() { $marginData = (new MarginFaker())->fake(); Auth::shouldReceive('user')->once()->andReturn((object)['id' => 999999]); $this->mock(DocumentService::class, function (MockInterface $mock) { $mock->shouldReceive('createDocument') ->once() ->andReturn(Str::random()); }); $request = MarginRequest::create('/api/public/documents/margin', 'POST', $marginData); $response = app(PublicController::class)->margin($request); $this->assertEquals(201, $response->getStatusCode()); }
解决方案
核心问题是直接调用控制器方法时,Laravel的表单请求验证流程没被触发。validated()方法依赖请求类完成验证后填充的有效数据,手动实例化请求并传入控制器的方式,不会自动启动验证逻辑,导致内部验证数据为空,进而抛出null相关错误。
有两种解决方式:
方式1:使用Laravel HTTP测试方法
放弃直接实例化控制器调用,改用框架提供的HTTP测试方法,它会自动处理请求的验证流程:
public function test_public_margin() { $marginData = (new MarginFaker())->fake(); Auth::shouldReceive('user')->once()->andReturn((object)['id' => 999999]); $this->mock(DocumentService::class, function (MockInterface $mock) { $mock->shouldReceive('createDocument') ->once() ->andReturn(Str::random()); }); $response = $this->post('/api/public/documents/margin', $marginData); $response->assertStatus(201); }
方式2:手动触发请求验证
如果必须直接调用控制器方法,需要手动调用请求类的validate()方法触发验证,确保validated()能获取到数据:
public function test_public_margin() { $marginData = (new MarginFaker())->fake(); Auth::shouldReceive('user')->once()->andReturn((object)['id' => 999999]); $this->mock(DocumentService::class, function (MockInterface $mock) { $mock->shouldReceive('createDocument') ->once() ->andReturn(Str::random()); }); $request = MarginRequest::create('/api/public/documents/margin', 'POST', $marginData); // 手动触发验证流程 $request->validate(); $response = app(PublicController::class)->margin($request); $this->assertEquals(201, $response->getStatusCode()); }
内容的提问来源于stack exchange,提问作者Vüsal Hüseynli
相关产品推荐
相关产品推荐

