19 March 2021
Recently, while building Lemon Squeezy I came across the issue of mocking Stripe classes in a Laravel application. If you've ever built any kind of billing system using Stripe in Laravel and want to test it (which you should) you'll understand the problem. Stripe objects tend to be large and complex and not easy to replicate.
However, Stripe recently released stripe-mock which is described as:
a mock HTTP server that responds like the real Stripe API. It can be used instead of Stripe's testmode to make test suites integrating with Stripe faster and less brittle.
Sounds great! This way I don't have to mock Stripe classes in my Laravel tests but can instead just point my Stripe API requests to the mock server and it will return valid Stripe responses.
Using stripe-mock
with Laravel turned out to be very simple. There are a bunch of different ways to run stripe-mock
(e.g. go, homebrew etc.) but they also provide a docker image for the server. As I'm using Laravel Sail (docker) for my local dev environment, that means I can just plug stripe-mock
into my docker-compose.yml
:
stripemock:
image: 'stripemock/stripe-mock:latest'
networks:
- sail
After a quick sail build
, stripe-mock
is now running along side my other containers. Now all I need to do is tell Laravel to point Stripe requests to this container instead of the real Stripe API during testing. This took a bit of digging into the Stripe PHP library to figure out but turned out to be relatively simple in the end. First, add a new api_base
entry under your stripe
config in config/services.php
:
'stripe' => [
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
'webhook' => [
'secret' => env('STRIPE_WEBHOOK_SECRET'),
],
'api_base' => env('STRIPE_API_BASE'), // <-- Add this
],
Next, in the boot
method of your AppServiceProvider.php
add the following:
public function boot()
{
if ($stripeApiBase = config('services.stripe.api_base')) {
\Stripe\Stripe::$apiBase = $stripeApiBase;
}
}
This will tell the Stripe library to use our new config variable as the $apiBase
for all Stripe requests. Finally, in your .env.testing
or phpunit.xml
set the new config variable to point to our stripe-mock
container:
STRIPE_API_BASE="stripemock:12111"
Port 12111
is what stripe-mock
uses for HTTP requests. That's it. Now your tests will run against the stripe-mock
API instead of the real Stripe API.
As stripe-mock
can be run as a docker container, it is also relatively simple to set up in CI environments. For example, to run stripe-mock
in a GitHub Action you can simply add it as another service
:
services:
stripemock:
image: stripemock/stripe-mock:latest
ports:
- 12111
Then when you run PHPUnit, set the API base as env
variable:
- name: Run tests
env:
STRIPE_API_BASE: "127.0.0.1:$@{{ job.services.stripemock.ports[12111] }}"
run: vendor/bin/phpunit
Subscribe to my newsletter to get infrequent updates in your inbox. Or follow me on Twitter.