Home > Software design >  How to test Stripe `SignatureVerificationError` in Python
How to test Stripe `SignatureVerificationError` in Python

Time:06-22

For python, the standard stripe webhook code example includes:

    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)

I've tried to test this with the following test that inherits from 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

This produces the following error which I dont understand:

> except stripe.error.SignatureVerificationError as e:
E TypeError: catching classes that do not inherit from BaseException is not allowed

How can I test that the signature verification error will have the expected effects?

CodePudding user response:

You can use the test cases in the stripe-python library as a reference. There are quite a number of test cases for signature verification errors.

CodePudding user response:

The problem was solved by changing the view code from:

except stripe.error.SignatureVerificationError as e:
        logger.error(f"*** Stripe invalid signature: {e = }")
        return HttpResponse(status=400)

to

except SignatureVerificationError as e:
        logger.error(f"*** Stripe invalid signature: {e = }")
        return HttpResponse(status=400)

and adding an additional import to the module:

import stripe
from stripe.error import SignatureVerificationError  # Add this line

I don't understand why this makes a difference, if anyone can explain I'd be grateful! I expect it's because I'm mocking the stripe object in the test which is clobbering too many things. Importing the error separately prevents it from being overridden by unittest.mock.patch, perhaps.

With these changes, the test runs as expected.

  • Related