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

Laravel中Mock TwoFactorAuth类失效问题求助

如何在Laravel测试中Mock直接new实例化的第三方类

问题场景

我需要在Laravel测试中Mock第三方类TwoFactorAuth,让它的verifyCode方法返回true(真实类该方法返回false)。但控制器中是直接通过new TwoFactorAuth()创建实例,导致常规的$this->mock()方法无法生效,new出来的还是真实类实例。虽然将Mock实例绑定到服务容器的方法能生效,但我不想修改控制器里的实例化逻辑,希望不改动业务代码就能完成Mock,通过控制器的测试用例。

控制器代码示例:

public function update(Request $request): Redirector|RedirectResponse
{
    $request->validate([
        'code' => 'required|string|min:6',
    ]);

    $tfa = new TwoFactorAuth();
    $valid = $tfa->verifyCode(auth()->user()->two_fa_secret_key, $request->input('code'));

    if ($valid === false) {
        return back()->withErrors('Code is invalid please try again.');
    }

    session()->forget('2fa-login');

    return redirect(route('dashboard'));
}

目标测试代码:

$this->post(route('admin.2fa'), ['code' => '123456'])
->assertSessionHasNoErrors()
->assertRedirect(route('dashboard'))

解决方案

使用Mockery的别名Mock(alias:前缀),它可以拦截new关键字创建类实例的操作,返回Mock对象,无需修改业务代码。

测试代码实现

public function test_2fa_verification_passes()
{
    // 用alias:前缀Mock类,拦截new操作返回Mock实例
    $this->mock('alias:' . TwoFactorAuth::class, function (MockInterface $mock) {
        $mock->shouldReceive('verifyCode')
            ->once() // 可选,验证方法被调用一次
            ->with(auth()->user()->two_fa_secret_key, '123456') // 可选,验证参数匹配
            ->andReturn(true);
    });

    // 执行测试请求
    $this->post(route('admin.2fa'), ['code' => '123456'])
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('dashboard'));
}

原理说明

  • alias:前缀是Mockery的特殊语法,它会创建一个类的动态别名,覆盖原类的实例化逻辑。当代码中执行new TwoFactorAuth()时,实际返回的是我们定义的Mock实例,而非真实类对象。
  • 这种方式不需要依赖Laravel服务容器,完美适配业务代码中直接new实例的场景,无需修改任何业务逻辑。

注意事项

  • 确保测试类继承自Laravel的TestCase,Laravel会自动处理Mockery的清理工作,避免测试污染。
  • 可以根据需求添加shouldReceive的额外约束,比如once()验证方法被调用次数,with()验证传入的参数是否符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:47:59