Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
Mocking Stripe signature checks in a pytest fixture#
I’m writing some code that accepts webhooks from Stripe. I wanted to simulate hits to this endpoint in my Django tests. Stripe uses a Stripe-Signature header and I wanted a way to mock my code so that I didn’t need to calculate the correct signature.
Here’s the pattern I used:
1import pytest2from unittest.mock import patch3
4@pytest.fixture5def mock_stripe_verify_header():6 with patch("stripe.WebhookSignature.verify_header") as mock_verify:7 mock_verify.return_value = None8 yield mock_verifyThis gives me a mock_stripe_verify_header fixture which I can pass to a test function in order to cause the verify_header() method in the Stripe library to always pass - as opposed to raising exceptions, which it does when the signature check fails. The corresponding Django view code that uses this API does so via stripe.Webhook.construct_event() and looks like this:
1@csrf_exempt2@require_POST3def stripe_webhook(request):4 payload = request.body5 sig_header = request.META["HTTP_STRIPE_SIGNATURE"]6 try:7 event = stripe.Webhook.construct_event(8 payload, sig_header, settings.STRIPE_WEBHOOK_SECRET9 )10 except (ValueError, stripe.error.SignatureVerificationError) as ex:11 # Invalid payload or signature12 return HttpResponse(status=400, content=json.dumps({"error": str(ex)}))Now I can write tests like this one:
1STRIPE_PAYLOAD = {2 "id": "evt_test123",3 "object": "event",4 "type": "payment_intent.succeeded",5 "created": 1630000000,6 "data": {7 "object": {8 "id": "pi_test123",9 "object": "payment_intent",10 "amount": 1000,11 "currency": "usd",12 }13 },14 "livemode": False,15 "api_version": "2020-08-27",16}17
18@pytest.mark.django_db19def test_valid_webhook(client, mock_stripe_verify_header):20 response = client.post(21 WEBHOOK_URL,22 data=json.dumps(STRIPE_PAYLOAD),23 content_type="application/json",24 HTTP_STRIPE_SIGNATURE="ignored",25 )26 assert response.status_code == 200Or if I want to test what happens when the signature check fails, I can use mock_stripe_verify_header.side_effect to cause it to trigger the expected exception:
1def test_invalid_webhook(client, mock_stripe_verify_header):2 mock_stripe_verify_header.side_effect = SignatureVerificationError(3 "Invalid signature", sig_header="ignored"4 )5 response = client.post(6 WEBHOOK_URL,7 data=json.dumps(STRIPE_PAYLOAD),8 content_type="application/json",9 HTTP_STRIPE_SIGNATURE="ignored",10 )11 assert response.status_code == 40012 assert response.content == b'{"error": "Invalid signature"}'