Vectorwyse
Tutorials

Mocking Third Party Libraries

Jeffrey Li
#laravel#testing#php#mocking
Feature image

Testing components that depend on third-party libraries can be painful. Take Stripe for example — you would need to set up test plans, customers, subscriptions, invoices, and more within Stripe’s test mode. This can get cumbersome quickly.

What if you could test your Stripe integration without ever hitting the Stripe API? By leveraging Laravel facades, you can create a mockable wrapper around any external service.

The Strategy

The approach has three parts:

  1. Create a wrapper class around the third-party SDK
  2. Register it as a singleton in the service container
  3. Create a facade for clean syntax and easy mocking

Step 1: Create a Wrapper Class

The wrapper class sets the API key once during initialization and dynamically forwards method calls to the appropriate Stripe classes:

<?php

namespace App\Wrappers;

class StripeWrapper
{
    public function __construct($secret)
    {
        \Stripe\Stripe::setApiKey($secret);
    }

    public function __call($class, $arguments)
    {
        $class = "\\Stripe\\$class";

        if (! class_exists($class)) {
            throw new \Exception("$class does not exist");
        }

        if (! count($arguments)) {
            throw new \Exception("Missing method name");
        }

        $method = $arguments[0];

        if (! method_exists($class, $method)) {
            throw new \Exception("$class::$method does not exist");
        }

        $arguments = count($arguments) > 1
            ? array_slice($arguments, 1)
            : [];

        return call_user_func_array([$class, $method], $arguments);
    }
}

When you call Stripe::Invoice('upcoming', ['customer' => $stripeId]), the wrapper translates this into \Stripe\Invoice::upcoming(['customer' => $stripeId]).

Step 2: Register as a Service Container Singleton

In your AppServiceProvider, bind the wrapper as a singleton so the API key is set once and reused:

public function register()
{
    $this->app->singleton(
        \App\Wrappers\StripeWrapper::class,
        function ($app) {
            return new \App\Wrappers\StripeWrapper(
                config('services.stripe.secret')
            );
        }
    );

    $this->app->alias(
        \App\Wrappers\StripeWrapper::class,
        'stripe_wrapper'
    );
}

Step 3: Create a Facade

Create a facade that points to the wrapper’s service container alias:

<?php

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Stripe extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'stripe_wrapper';
    }
}

As the Laravel documentation states, facades serve as “static proxies” to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.

Usage

In Production Code

use App\Facades\Stripe;

$invoice = Stripe::Invoice('upcoming', ['customer' => $stripeId]);

In Tests

Now you can mock the entire Stripe integration without making a single API call:

use App\Facades\Stripe;

public function testUpcomingInvoice()
{
    Stripe::shouldReceive('Invoice')
        ->once()
        ->with('upcoming', ['customer' => 'cus_XXX'])
        ->andReturn($mockedResponse);

    // Run your code that calls Stripe::Invoice(...)
    // and assert against the mocked response
}

Why This Works

This pattern works because of how Laravel’s facade system is built. When you call Stripe::shouldReceive(...), Laravel swaps the real singleton with a Mockery instance. Your production code calls the facade the same way, but in tests, the mock intercepts the call and returns whatever you’ve configured — no HTTP requests, no external dependencies.

Wrapping Up

This wrapper + facade pattern isn’t limited to Stripe. You can apply it to any PHP SDK — Twilio, SendGrid, AWS, you name it. The key benefits are:

← Back to Blog