Laravel单元测试中如何Mock Cashier的defaultPaymentMethod()方法?
问题原因分析
你当前的Mock未生效,核心原因是控制器中使用Cashier::findBillable(\Auth::user()->stripe_id)获取的是全新的User实例,并非你测试代码中创建并Mock的$this->user对象。Cashier的findBillable方法会根据传入的stripe_id重新构建/查询得到Billable实例,导致你提前Mock的方法无法关联到这个新实例上。
解决方案
以下两种方法可以解决这个问题:
方法一:Mock Cashier的findBillable静态方法
直接让Cashier::findBillable返回你预先Mock好的User实例,确保控制器拿到的是带有Mock方法的对象:
public function test_paymentmethod_id_is_retrieved() { // 构造测试用的支付方法实例 $defaultPaymentMethod = new BankAccount(); $defaultPaymentMethod->id = 'test-payment-method-id'; // Mock User实例的defaultPaymentMethod方法 $mockUser = Mockery::mock(User::class)->makePartial(); $mockUser->shouldReceive('defaultPaymentMethod') ->once() ->andReturn($defaultPaymentMethod); // Mock Cashier的findBillable静态方法,返回我们的Mock实例 Cashier::shouldReceive('findBillable') ->with($this->user->stripe_id) ->once() ->andReturn($mockUser); // 发起请求 $response = $this->actingAs($this->user)->post($this->url); // 断言结果(注意修正原测试中的拼写错误:asertEquals → assertEquals) $this->assertEquals($response->getContent(), $defaultPaymentMethod->id); }
方法二:简化控制器逻辑(推荐,如果业务允许)
如果你的User模型已经引入了Billable trait,完全可以直接使用Auth::user()获取实例,无需通过Cashier::findBillable二次查询:
修改控制器代码
public function exec() { $user = \Auth::user(); $paymentMethodId = $user->defaultPaymentMethod()->id; return $paymentMethodId; }
修改测试代码
此时actingAs的用户就是控制器中使用的实例,直接Mock该实例的方法即可:
public function test_paymentmethod_id_is_retrieved() { $defaultPaymentMethod = new BankAccount(); $defaultPaymentMethod->id = 'test-payment-method-id'; // 直接Mock当前登录用户的defaultPaymentMethod方法 $this->user->shouldReceive('defaultPaymentMethod') ->once() ->andReturn($defaultPaymentMethod); $response = $this->actingAs($this->user)->post($this->url); $this->assertEquals($response->getContent(), $defaultPaymentMethod->id); }
额外注意点
- 原测试代码中存在拼写错误:
asertEquals需改为assertEquals - 若控制器返回的是JSON格式响应,需使用
$response->json()替代$response->getContent()来获取返回值
内容的提问来源于stack exchange,提问作者Sau Rai
相关产品推荐
相关产品推荐

