Laravel-Stripe-PHP测试:Mock StripeClient及方法实现测试覆盖
Mock Stripe Client 实现测试覆盖的方案
1. 先重构代码:用依赖注入替代直接实例化
要Mock StripeClient,首先得避免在业务代码里直接new StripeClient()——这种硬编码实例化的方式会让Mock变得困难。改成通过构造函数注入StripeClient,让测试时能轻松替换成Mock实例。
原代码(难Mock):
class PaymentService { public function createPaymentIntent(array $params) { $stripe = new StripeClient('sk_test_xxx'); return $stripe->paymentIntents->create($params); } }
重构后代码(易Mock):
class PaymentService { private $stripeClient; // 构造函数注入StripeClient实例 public function __construct(\Stripe\StripeClient $stripeClient) { $this->stripeClient = $stripeClient; } public function createPaymentIntent(array $params) { return $this->stripeClient->paymentIntents->create($params); } }
2. 用PHPUnit Mock StripeClient及PaymentIntents
Stripe SDK是链式调用(stripe->paymentIntents->create()),所以需要Mock两层:StripeClient本身,以及它返回的PaymentIntentService实例。
测试示例代码
use PHPUnit\Framework\TestCase; use Stripe\StripeClient; use Stripe\Service\PaymentIntentService; use Stripe\PaymentIntent; class PaymentServiceTest extends TestCase { public function testCreatePaymentIntent() { // 1. Mock PaymentIntentService,预设create方法的返回值 $mockPaymentIntent = $this->createMock(PaymentIntent::class); $mockPaymentIntent->method('__get')->with('id')->willReturn('pi_123456'); $mockPaymentIntentService = $this->createMock(PaymentIntentService::class); $mockPaymentIntentService->expects($this->once()) ->method('create') ->with([ 'amount' => 1000, 'currency' => 'usd', 'payment_method_types' => ['card'] ]) ->willReturn($mockPaymentIntent); // 2. Mock StripeClient,让它返回上面Mock的PaymentIntentService $mockStripeClient = $this->createMock(StripeClient::class); $mockStripeClient->method('__get') ->with('paymentIntents') ->willReturn($mockPaymentIntentService); // 3. 注入Mock实例,执行测试方法 $paymentService = new PaymentService($mockStripeClient); $result = $paymentService->createPaymentIntent([ 'amount' => 1000, 'currency' => 'usd', 'payment_method_types' => ['card'] ]); // 4. 断言结果符合预期 $this->assertEquals('pi_123456', $result->id); } }
3. 链式调用Mock的注意点
- StripeClient通过魔术方法
__get返回各类服务(比如paymentIntents对应PaymentIntentService),所以Mock时要针对__get方法,传入服务名称并返回Mock的服务实例。 - 可以通过
expects($this->once())验证目标方法是否被调用,with()匹配传入的参数,确保业务逻辑传参正确。
4. 验证测试覆盖
用PHPUnit生成代码覆盖率报告,确认业务代码是否被完全覆盖:
phpunit --coverage-html coverage-report
打开生成的coverage-report/index.html,就能查看PaymentService中每一行代码的覆盖情况。
框架适配(以Laravel为例)
如果用Laravel这类依赖注入框架,可以在测试的setUp方法中绑定Mock实例到容器:
protected function setUp(): void { parent::setUp(); $mockPaymentIntentService = $this->createMock(PaymentIntentService::class); // 配置Mock逻辑... $mockStripeClient = $this->createMock(StripeClient::class); $mockStripeClient->method('__get')->with('paymentIntents')->willReturn($mockPaymentIntentService); $this->app->bind(StripeClient::class, fn() => $mockStripeClient); }
这样测试时框架会自动注入Mock实例,无需手动传入。
内容的提问来源于stack exchange,提问作者tcgkn
相关产品推荐
相关产品推荐

