Mocking the Paystack API in PHPUnit
In Laravel: use Http::fake() to intercept Paystack API calls before they hit the network. Return fake responses for the initialize and verify endpoints. In plain PHP: inject a Paystack client interface and use Mockery::mock() in tests. For webhook testing, generate a valid HMAC signature in your test and POST directly to your webhook controller.
Laravel Http::fake() for Paystack
// tests/Feature/PaymentTest.php
use IlluminateSupportFacadesHttp;
use TestsTestCase;
class PaymentTest extends TestCase
{
public function test_checkout_returns_authorization_url(): void
{
Http::fake([
'https://api.paystack.co/transaction/initialize' => Http::response([
'status' => true,
'data' => [
'authorization_url' => 'https://checkout.paystack.com/test',
'access_code' => 'test_access',
'reference' => 'ref_test_001',
],
], 200),
]);
$response = $this->postJson('/api/checkout', [
'email' => 'user@test.com',
'amount' => 10000,
'order_id' => 1,
]);
$response->assertStatus(200)
->assertJson(['authorization_url' => 'https://checkout.paystack.com/test']);
}
public function test_webhook_processes_charge_success(): void
{
$order = Order::factory()->create(['status' => 'pending']);
$secret = config('services.paystack.secret_key');
$payload = json_encode([
'event' => 'charge.success',
'data' => [
'reference' => 'ref_test_001',
'amount' => 1000000,
'status' => 'success',
'metadata' => ['order_id' => $order->id],
],
]);
$signature = hash_hmac('sha512', $payload, $secret);
$response = $this->withHeaders([
'x-paystack-signature' => $signature,
])->postJson('/webhook/paystack', json_decode($payload, true));
$response->assertStatus(200);
$this->assertDatabaseHas('orders', [
'id' => $order->id,
'status' => 'paid',
]);
}
}
Plain PHP with Mockery
// Plain PHP test with Mockery
use PHPUnitFrameworkTestCase;
use Mockery;
class PaymentServiceTest extends TestCase
{
public function test_returns_checkout_url_on_success(): void
{
$paystackMock = Mockery::mock(PaystackClient::class);
$paystackMock->shouldReceive('initializeTransaction')
->once()
->with(Mockery::on(fn($args) => $args['email'] === 'user@test.com'))
->andReturn([
'status' => true,
'data' => ['authorization_url' => 'https://checkout.paystack.com/test'],
]);
$service = new PaymentService($paystackMock);
$result = $service->createCheckout('user@test.com', 10000);
$this->assertEquals('https://checkout.paystack.com/test', $result['url']);
}
protected function tearDown(): void
{
Mockery::close();
}
}
Learn More
This guide is part of the Paystack testing guide.
Key Takeaways
- ✓In Laravel, use Http::fake() to intercept Paystack API calls — no real HTTP request is made.
- ✓Match the fake response structure to what Paystack actually returns: { status: true, data: { reference, amount, status } }.
- ✓For webhook tests, generate the HMAC SHA512 signature in the test: hash_hmac("sha512", $body, $secret).
- ✓Use Mockery::mock() or PHPUnit createMock() if you have a Paystack service class — mock the interface, not the HTTP client.
- ✓Test the decline scenario by returning { status: false, data: { gateway_response: "Do Not Honor" } } from your Http fake.
- ✓In Laravel, use RefreshDatabase trait so each test starts with a clean database state.
Frequently Asked Questions
- Does Http::fake() intercept all Paystack API calls in Laravel?
- Http::fake() intercepts calls made through Laravel's HTTP client (Http:: facade or the underlying Guzzle client that Laravel wraps). If your Paystack integration uses curl directly or a third-party SDK that does not use Laravel's HTTP client, Http::fake() will not intercept it — use Mockery instead.
- How do I test the Paystack webhook signature validation in PHPUnit?
- Generate a valid HMAC SHA512 signature in your test using the same algorithm your handler uses: $signature = hash_hmac("sha512", $rawBody, $secret). Set this as the x-paystack-signature header in your test POST request. To test invalid signature rejection, change one character of the signature and assert the handler returns 401.
- What PHPUnit version is required for these patterns?
- PHPUnit 10+ (the current standard with Laravel 11+). The patterns shown work with PHPUnit 9 and 10. Http::fake() requires Laravel 7+ — it was introduced with Laravel's built-in HTTP client.
- Should I use Http::fake() or a Paystack SDK mock?
- If you call the Paystack API directly via Laravel's Http client, use Http::fake(). If you use a Paystack PHP SDK (like unicodeveloper/paystack or yabacon/paystack-php), mock the SDK class with Mockery — it has its own HTTP layer that Http::fake() may not intercept.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon