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

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);
}
额外注意点
  1. 原测试代码中存在拼写错误:asertEquals需改为assertEquals
  2. 若控制器返回的是JSON格式响应,需使用$response->json()替代$response->getContent()来获取返回值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:00:28