Using Stripe's Mock Server

August 22nd, 2022

Chipper CI is continuous integration, just for Laravel. Give it a try - free!

"Don't mock what you don't own". Technically we're about to do that, but we're going to use an official mock API from Stripe. So it's all OK! Or something.

Let's see how to use Stripe's Mock API to help us run our tests without having to hit Stripe's actual API.

The main reason to do this is:

  1. Speed - this is faster than hitting Stripe's API (presumable in testing you'll be using their test mode). Hitting stripes API (even in test mode) to test making charges is very slow.
  2. Fidelity - We'll still allow our code to make "real" API requests and be reasonable certain the responses we get back will be the same as making a call to Stripe's production API

Why Hit Stripe's API at All?

I generally try to set up my code to I can mock out the code paths that might make API calls to other services.

However, billing logic is important. Extremely important!

I am in the camp of having at least a few tests actually talks to Stripe's API (in test mode).

The trade offs are:

  1. The odd test might fail if Stripe is having issues (rare!)
  2. Tests making api calls will be slower (common!)

So I like having a limited set of tests that make actual API calls.

However, it's sometimes useful to make either some or all of your calls to Stripe's API faster. We can do this with Stripe's mock API!

Watch Out

This isn't perfect. There may be cases where you want to just hit Stripe's real API and eat the time cost.

Note the caveats mentioned in the GitHub repository's read me.

These mean your tests using this API may need to expect some specific sample responses.

Using Stripe Mock

This is a Golang project, so it's relatively easy to get this running. You can use brew, download the binary, or run it in Docker.

If you have go installed, it may be easiest to just run:

# Install via "go install" will download, build, and 
# install the program to your $GOPATH
go install github.com/stripe/stripe-mock@latest

# Then you can run it
stripe-mock -http-port 12111

However, I'll show running it in Docker as we'll end up using this method in Chipper CI in our pipeline as well.

docker run --rm -it -p 12111:12111 \
    stripe/stripe-mock:latest

Once this is running, and listening for http requests on port 12111, we can try to make a request to it.

It won't care about the secret key we send it:

curl -i http://localhost:12111/v1/charges \
    -H "Authorization: Bearer sk_test_123"

Mocking Stripe in Laravel

Our Laravel application will need a bit of tweaking to make Stripe send API requests to this test API.

What I prefer to do is manually set the mock API per test, similar to how we would mock a specific Laravel API (Mail::fake, Event::fake(), etc.

This gives me the flexibility to decide which tests can be "fast" by using our mock Stripe API. Any test we want to hit their "real" API can still do so if you need.

We can update our .env file to set a new value:

STRIPE_API_BASE="http://localhost:12111"

Then we need some configuration to get this value. It might be your config/services.php or config/cashier.php or something else! It depends on your usage. The cashier.php is the most likely place!

# Some of file config/cashier.php
return [
    // These already exist
    'key' => env('STRIPE_KEY'),

    'secret' => env('STRIPE_SECRET'),
    
    // I added this one
    'api_base' => env('STRIPE_API_BASE'),
];

Then, in our tests, we can decide when to use this base URL.

public function test_stripe_gets_charges()
{
    // Tell Stripe (via Cashier) to 
    // use the Stripe Mock API
    Cashier::$apiBaseUrl = config('cashier.api_base');

    // A pretend route that lists the
    // current user charges from Stripe
    $response = $this->actingAs(User::first())
        ->get(route('user.charges'));

    $response->assertSuccessful();
}

Note that if you're not using Cashier, your PHP code may instead be more like this:

\Stripe\Stripe::$apiBase = $stripeApiBase;

Using Stripe Mock in Chipper CI

Using Stripe Mock in Chipper CI isn't really any different. Most of the work resolves making sure your code base can work with it successfully.

You can go about it two ways:

  1. Download the right binary and run Stripe Mock directly
  2. Use Docker to spin up Stripe Mock
# Sample .chipperci.yml file
pipeline:

  - name: setup w/ out Docker
    cmd: | 
      wget https://github.com/stripe/stripe-mock/releases/download/v0.142.0/stripe-mock_0.142.0_linux_amd64.tar.gz
      tar -xvjf stripe-mock_0.142.0_linux_amd64.tar.gz
      ./stripe-mock -http-port 12111 &
      ###
      ## Now make requests to localhost:12111
      #
      curl -i http://localhost:12111/v1/charges \
          -H "Authorization: Bearer sk_test_123"

  - name: setup w/ Docker
    cmd: | 
      docker run --rm -d -p 12111:12111 stripe/stripe-mock:latest
      ###
      ## Now make requests to $DOCKER_HOST_IP:12111
      #
      curl -i http://$DOCKER_HOST_IP:12111/v1/charges \
          -H "Authorization: Bearer sk_test_123"

Note that the two methods require a different value for your STRIPE_API_BASE environment variable. One of the following:

  1. STRIPE_API_BASE="127.0.0.1:12111" - If not using Docker
  2. STRIPE_API_BASE="${DOCKER_HOST_IP}:12111" - If using Docker
Try out Chipper CI!
Chipper CI is the easiest way to test and deploy your Laravel applications. Try it out - it's free!