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

Laravel中如何测试控制器是否使用指定FormRequest

验证控制器是否使用指定FormRequest的测试方案

你遇到的问题核心是:用spy监听MyStoreRequest时,默认不会执行原类的validated()方法,导致返回null,控制器调用create()时参数错误;但不加状态断言又无法确认测试是否真的触发了控制器逻辑。

解决思路很直接:让spy的validated()方法返回合法的数组,这样控制器能正常走完流程,状态断言就能通过,同时还能验证FormRequest是否被调用。

完整测试代码示例

public function test_store_action_uses_my_store_request()
{
    // 创建MyStoreRequest的间谍,并指定validated()返回合法数据
    $requestSpy = $this->spy(MyStoreRequest::class);
    $validatedData = [
        'name' => '测试用户',
        'email' => 'test@example.com',
        // 其他模型需要的字段...
    ];
    $requestSpy->shouldReceive('validated')->andReturn($validatedData);

    // 发送请求(这里的请求参数可以随便填,因为我们已经mock了validated的返回)
    $response = $this->post(route('your.resource.store'), [
        'name' => '随便填的无效数据',
        'email' => 'invalid-email',
    ]);

    // 现在可以正常断言响应状态了
    $response->assertStatus(302); // 或者201,根据你的控制器返回逻辑调整

    // 核心断言:确认FormRequest的validated方法被调用过,说明请求确实使用了该类
    $requestSpy->shouldHaveReceived('validated');
}

为什么这么做能解决问题

  • 默认情况下,spy如果没有指定方法的返回值,会返回null,这就导致控制器里$request->validated()拿到null,传给Model::create()时触发参数错误。
  • 手动指定validated()的返回值后,控制器逻辑能正常执行,模型创建成功,响应状态断言自然能通过。
  • 最后的shouldHaveReceived('validated')断言是关键:它能直接证明MyStoreRequest被注入并调用了核心方法,完全满足你“验证请求是否实际使用指定FormRequest”的需求。

另一种可选方案(partial mock)

如果你不想mockvalidated()的返回,也可以用部分模拟,让原类的验证逻辑正常执行,但依然监听方法调用:

public function test_store_uses_my_store_request()
{
    $requestMock = $this->partialMock(MyStoreRequest::class);
    $requestMock->shouldReceive('validated')->once();

    // 这里要传符合验证规则的参数,因为partial mock会执行原类的验证逻辑
    $response = $this->post(route('your.resource.store'), [
        'name' => '合法用户名',
        'email' => 'valid@example.com',
    ]);

    $response->assertStatus(302);
}

这种方案适合你偶尔想兼顾验证逻辑的情况,但如果你的目标只是确认FormRequest被使用,第一种方案更简洁,不需要关心验证规则。

内容的提问来源于stack exchange,提问作者IGP

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:32:52