You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 05:20:48