Python如何测试Stripe SignatureVerificationError异常处理逻辑
问题场景
对于Python开发,Stripe官方给出的标准Webhook代码示例如下:
event = None try: event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret) except ValueError as e: logger.error(f"*** Stripe invalid payload: {e = }") return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: logger.error(f"*** Stripe invalid signature: {e = }") return HttpResponse(status=400)
编写的继承自Django TestCase的测试用例如下,目的是验证签名验证错误的处理逻辑:
class TestStripeWebhookView(TestCase): @mock.patch("logging.Logger.error") @mock.patch("lettergun.apps.payments.views.create_order") @mock.patch("lettergun.apps.payments.views.stripe") def test_signature_verification_error(self, stripe, create_order, error): stripe.Webhook.construct_event.side_effect = SignatureVerificationError data = { "type": "placeholder", } response = self.client.get( reverse("payments:stripe_webhook"), data, HTTP_ACCEPT="application/json", HTTP_STRIPE_SIGNATURE='placeholder_signature"}', ) error.assert_called_with(f"*** Stripe invalid signature: e = an error message") assert not create_order.called assert response.status_code == 400
运行测试时抛出如下错误:
> except stripe.error.SignatureVerificationError as e: E TypeError: catching classes that do not inherit from BaseException is not allowed
错误原因
报错核心原因是用@mock.patch("lettergun.apps.payments.views.stripe")替换了视图文件中引入的整个stripe模块,此时视图代码里访问的stripe.error.SignatureVerificationError不再是Stripe SDK提供的真实异常类,而是mock生成的MagicMock实例。Python规定except关键字后跟随的异常类必须继承自BaseException,MagicMock不满足这个要求,因此抛出类型错误。
除此之外原测试代码还有两个逻辑问题:
- 给
side_effect赋值时直接传了SignatureVerificationError类引用,没有正确导入真实类也没有实例化,即使mock范围正确也无法正确触发异常捕获逻辑 - 测试Webhook接口用了GET请求,而Stripe的Webhook回调只会发送POST请求
修正方案
- 不要全量mock整个stripe模块,只mock需要替换行为的
stripe.Webhook.construct_event方法,保留stripe其他属性(包括异常类)的真实实现 - 触发异常时传入真实实例化的
stripe.error.SignatureVerificationError对象,该异常构造需要传入两个必填参数:错误信息、请求签名头内容 - 把测试请求改为POST请求,符合Stripe Webhook的实际调用逻辑
修正后的测试代码参考:
import stripe # 其余导入省略:TestCase、mock、reverse、视图相关依赖等 class TestStripeWebhookView(TestCase): @mock.patch("logging.Logger.error") @mock.patch("lettergun.apps.payments.views.create_order") # 仅mock需要替换逻辑的construct_event方法,不mock整个stripe模块 @mock.patch("lettergun.apps.payments.views.stripe.Webhook.construct_event") def test_signature_verification_error(self, mock_construct_event, mock_create_order, mock_log_error): test_sig = 'placeholder_signature' # 抛出真实实例化的签名验证异常 mock_construct_event.side_effect = stripe.error.SignatureVerificationError( "an error message", test_sig ) data = { "type": "placeholder", } # 改用POST请求发起测试 response = self.client.post( reverse("payments:stripe_webhook"), data=data, content_type="application/json", HTTP_STRIPE_SIGNATURE=test_sig, ) mock_log_error.assert_called_with(f"*** Stripe invalid signature: e = an error message") assert not mock_create_order.called assert response.status_code == 400
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

