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
相关产品推荐
相关产品推荐

