Testing
Strategies for testing your Paystack integration.
Unit Testing API Calls
Mock the HTTP layer so tests never hit the real Paystack API:
from django.test import TestCase
from unittest.mock import patch, MagicMock
from djpaystack import PaystackClient
class TransactionTestCase(TestCase):
def setUp(self):
self.client = PaystackClient()
@patch('djpaystack.api.base.requests.Session.request')
def test_initialize_transaction(self, mock_request):
mock_request.return_value = MagicMock(
status_code=200,
json=lambda: {
'status': True,
'message': 'Authorization URL created',
'data': {
'authorization_url': 'https://checkout.paystack.com/...',
'access_code': 'ACCESS_CODE',
'reference': 'UNIQUE_REF',
},
},
)
response = self.client.transactions.initialize(
email='test@example.com',
amount=50000,
)
self.assertTrue(response['status'])
self.assertIn('authorization_url', response['data'])
@patch('djpaystack.api.base.requests.Session.request')
def test_verify_transaction(self, mock_request):
mock_request.return_value = MagicMock(
status_code=200,
json=lambda: {
'status': True,
'data': {
'reference': 'UNIQUE_REF',
'amount': 50000,
'status': 'success',
},
},
)
response = self.client.transactions.verify('UNIQUE_REF')
self.assertTrue(response['status'])
self.assertEqual(response['data']['status'], 'success')
Integration Testing
Use test credentials (sk_test_...) to hit the real API in a CI
environment:
from django.test import TestCase, override_settings
from djpaystack import PaystackClient
@override_settings(PAYSTACK={
'SECRET_KEY': 'sk_test_...',
'PUBLIC_KEY': 'pk_test_...',
})
class IntegrationTestCase(TestCase):
def test_payment_flow(self):
client = PaystackClient()
init = client.transactions.initialize(
email='test@example.com', amount=50000,
)
self.assertTrue(init['status'])
View Testing
from django.test import TestCase, Client
from unittest.mock import patch
class PaymentViewTestCase(TestCase):
def setUp(self):
self.http = Client()
@patch('myapp.views.PaystackClient')
def test_checkout_view(self, MockClient):
MockClient.return_value.transactions.initialize.return_value = {
'status': True,
'data': {
'authorization_url': 'https://checkout.paystack.com/...',
'reference': 'TEST_REF',
},
}
response = self.http.post('/checkout/', {
'email': 'test@example.com',
'amount': '500',
})
self.assertEqual(response.status_code, 302)
Webhook Testing
Generate a correctly signed request from the test suite:
import hmac, hashlib, json
from django.test import TestCase, Client, override_settings
from django.urls import reverse
SECRET = 'sk_test_xxx'
@override_settings(PAYSTACK={'SECRET_KEY': SECRET})
class WebhookTestCase(TestCase):
def _signed_post(self, payload_dict):
body = json.dumps(payload_dict)
sig = hmac.new(
SECRET.encode(), body.encode(), hashlib.sha512,
).hexdigest()
return self.client.post(
reverse('paystack-webhook'),
data=body,
content_type='application/json',
HTTP_X_PAYSTACK_SIGNATURE=sig,
)
def test_charge_success(self):
resp = self._signed_post({
'event': 'charge.success',
'data': {
'reference': 'TEST_REF',
'amount': 50000,
'customer': {'email': 'test@example.com'},
'status': 'success',
},
})
self.assertEqual(resp.status_code, 200)
def test_invalid_signature_rejected(self):
resp = self.client.post(
reverse('paystack-webhook'),
data='{}',
content_type='application/json',
HTTP_X_PAYSTACK_SIGNATURE='bad',
)
self.assertEqual(resp.status_code, 401)
Using paystack_webhook_event
Fire a simulated webhook at your running dev server from the command line:
# Send a charge.success event with default sample data
python manage.py paystack_webhook_event charge.success
# Custom reference and amount
python manage.py paystack_webhook_event charge.success \
--reference order_123 --amount 75000
# Completely custom payload
python manage.py paystack_webhook_event charge.success \
--data '{"reference": "custom", "amount": 50000}'
See Local Webhook Testing for the full workflow.
Testing Utilities
WebhookTester (in djpaystack.dev.webhook_tester) sends signed
webhook requests programmatically:
from djpaystack.dev.webhook_tester import WebhookTester
tester = WebhookTester(
base_url='http://localhost:8000',
secret_key='sk_test_xxx',
)
response = tester.send_test_webhook(
event='charge.success',
data={'reference': 'test-123', 'amount': 50000},
)
assert response.status_code == 200
Best Practices
Use test credentials — never live keys in CI or local dev.
Mock external calls — patch
requests.Session.requestto keep tests fast and deterministic.Test success and failure paths — verify both happy-path and error responses.
Keep tests isolated — use
override_settingsso each test has its own config.Test signal handlers — send signals manually and assert side-effects.
Run the full suite before pushing —
python -m pytest djpaystack/tests/ -v.Test at multiple levels (unit, integration, end-to-end)
import factory
from djpaystack.models import Transaction
class TransactionFactory(factory.django.DjangoModelFactory):
class Meta:
model = Transaction
reference = factory.Sequence(lambda n: f'TEST_REF_{n}')
amount = 50000
customer_email = 'test@example.com'
status = 'pending'