McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Mocking the Paystack API in Pytest
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Mocking the Paystack API in Pytest

In Python, mock Paystack API calls using @patch("requests.post") or @patch("requests.get") decorators in pytest. Return a Mock object with a .json() method that returns your fake Paystack response. For webhook testing, use hashlib and hmac to generate a valid signature in your test, then POST to your webhook view.

In this article

  1. 1. Mocking Paystack API Calls with unittest.mock
  2. 2. Testing Webhook Handlers in Django
  3. 3. Learn More

Mocking Paystack API Calls with unittest.mock

# tests/test_payment.py
import pytest
from unittest.mock import patch, MagicMock


@patch('myapp.payments.requests.post')
def test_initialize_transaction_returns_auth_url(mock_post):
    mock_response = MagicMock()
    mock_response.json.return_value = {
        'status': True,
        'data': {
            'authorization_url': 'https://checkout.paystack.com/test',
            'reference': 'ref_test_001',
        }
    }
    mock_post.return_value = mock_response

    from myapp.payments import initialize_transaction
    result = initialize_transaction(email='user@test.com', amount=100000)

    assert result['data']['authorization_url'] == 'https://checkout.paystack.com/test'
    mock_post.assert_called_once()
    call_kwargs = mock_post.call_args[1]
    assert 'Bearer' in call_kwargs['headers']['Authorization']


@patch('myapp.payments.requests.get')
def test_verify_transaction_success(mock_get):
    mock_response = MagicMock()
    mock_response.json.return_value = {
        'status': True,
        'data': {
            'status': 'success',
            'amount': 100000,
            'reference': 'ref_test_001',
        }
    }
    mock_get.return_value = mock_response

    from myapp.payments import verify_transaction
    result = verify_transaction('ref_test_001')

    assert result['data']['status'] == 'success'

Testing Webhook Handlers in Django

# tests/test_webhook.py
import hashlib
import hmac
import json
import pytest
from django.test import TestCase, Client


class PaystackWebhookTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.secret = 'sk_test_fake_secret'

    def make_signature(self, body: str) -> str:
        return hmac.new(
            self.secret.encode('utf-8'),
            body.encode('utf-8'),
            hashlib.sha512
        ).hexdigest()

    def test_valid_charge_success_webhook(self):
        payload = {
            'event': 'charge.success',
            'data': {
                'reference': 'ref_001',
                'amount': 100000,
                'status': 'success',
                'metadata': {'order_id': 1},
            }
        }
        body = json.dumps(payload)
        sig = self.make_signature(body)

        response = self.client.post(
            '/webhook/paystack/',
            data=body,
            content_type='application/json',
            HTTP_X_PAYSTACK_SIGNATURE=sig,
        )
        self.assertEqual(response.status_code, 200)

    def test_invalid_signature_rejected(self):
        payload = {'event': 'charge.success', 'data': {}}
        response = self.client.post(
            '/webhook/paystack/',
            data=json.dumps(payload),
            content_type='application/json',
            HTTP_X_PAYSTACK_SIGNATURE='invalid_sig',
        )
        self.assertEqual(response.status_code, 401)

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Learn More

This guide is part of the Paystack testing guide.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Use @patch("requests.post") to intercept outbound calls to the Paystack API in Python tests.
  • ✓The mock must have a .json() method — use MagicMock and set return_value.json.return_value to your fake response dict.
  • ✓Test webhook signature validation in Python: hmac.new(secret.encode(), body.encode(), hashlib.sha512).hexdigest().
  • ✓Test both success and failure cases — mock different return values in separate test functions.
  • ✓In Django tests, use self.client.post() to send webhook requests to your view; in Flask tests, use app.test_client().post().
  • ✓Use pytest fixtures to set environment variables (monkeypatch.setenv) for PAYSTACK_SECRET_KEY without affecting other tests.

Frequently Asked Questions

Should I use responses library or unittest.mock for Paystack API mocking in Python?
Both work. unittest.mock.patch is built-in and sufficient for most cases. The responses library (pip install responses) is cleaner if you have many tests mocking different URLs — it matches mock responses to specific URL patterns. For Paystack specifically, @patch("requests.post") is usually enough.
How do I test async Paystack calls with aiohttp in pytest?
Use pytest-asyncio and aioresponses (pip install aioresponses). In your test: from aioresponses import aioresponses. Then: with aioresponses() as m: m.post("https://api.paystack.co/transaction/initialize", payload={...}). This intercepts aiohttp calls without real network requests.
How do I inject the test secret key without hardcoding it?
Use pytest monkeypatch in a fixture: @pytest.fixture(autouse=True) def set_paystack_secret(monkeypatch): monkeypatch.setenv("PAYSTACK_SECRET_KEY", "sk_test_fake"). This sets the environment variable for the duration of the test without persisting it.
What is the correct Python HMAC signature for Paystack webhooks?
import hashlib, hmac. Then: sig = hmac.new(secret.encode("utf-8"), body.encode("utf-8"), hashlib.sha512).hexdigest(). The body must be the exact raw bytes received — do not parse and re-serialize the JSON, as this may change spacing and invalidate the signature.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Testing Paystack Integrations: The Complete Guide

A complete guide to testing Paystack integrations at every level: test mode, test cards, unit tests with mocks, integration tests, end-to-end flows with Playwright, webhook simulation, contract testing, CI pipelines, staging environments, load testing, and coverage targets for payment code.

Read more

Simulating Declined Cards on Paystack

A card decline is one of the most common failure states in a payment flow, and your application must handle it gracefully. This guide shows how to simulate specific card declines in Paystack test mode and how to verify your decline handling code works correctly.

Read more

Integration Testing Paystack Flows End to End

Integration tests for Paystack test the real flow — your backend calls the actual Paystack test API, a webhook fires to your server, and your database is updated. Unlike unit tests with mocks, integration tests catch issues that only appear when the real API is involved.

Read more

Seeding Test Data for a Payments Feature

Good test data is essential for testing payment features. This guide covers creating Paystack test mode resources (plans, subaccounts, split codes) and seeding your application database with matching payment records for realistic test scenarios.

Read more

Paystack Duplicate Transaction Reference Error

Paystack returns "Duplicate Transaction Reference" when you send a reference that already exists. This guide covers every cause, from reused references to retry logic without regeneration, and gives you production-safe patterns for generating unique references every time.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.