How to mock the Laravel Application instance

A not-for-everyday technique that can occasionally come in very handy.

Ralph J. Smit Laravel Software Engineer

As I've written earlier, I consider testing a(n) (Laravel) application a critical part of development. A handy testing tool is mocking other Laravel classes.

In some situations it might be handy to mock the Laravel Application instance. That sounds very heavy, so it might not always be a good idea.

My use case was testing whether an Eloquent Global Scope was applied, based on whether or not we were running unit tests. Something like this:

use Illuminate\Support\Facades\App;
 
if ( ! App::runningUnitTests() ) {
static::addGlobalScope(/** */);
}

Mocking the Laravel container instance

The above code only applied an Eloquent scope when the application wasn't running tests.

How should we test this logic? The answer lies in the fact that I'm using the App facade, instead of the app() helper. A facade can be relatively easily mocked. Thus, we can also quite easily mock calls to the Container, whilst not having to do some elaborate mocking call. So, instead of mocking app(), we're mocking on the Facade level.

// Mock the call to the `runningUnitTests` method.
App::shouldReceive('runningUnitTests')->andReturnFalse();

And that's really all that is to mocking the application instance! Very easy and straight from the facade.

This technique can also be very useful for package authors to mock calls to stuff like App::environment(), App::getNamespace(), etc.

PS: testing Eloquent global scopes

If you were interested in testing Eloquent global scopes, you should not forget to call YourModel::clearBootedModels() after making changes to the environment. Otherwise the boot() method will not be evaluated again, and thus your scope not applied again:

User::factory()->create();
 
expect(User::count())->toBe(1);
 
App::shouldReceive('runningUnitTests')->andReturnFalse();
 
User::clearBootedModels();
 
expect(User::count())->toBe(0);

Published by Ralph J. Smit on in Laravel . Last updated on 11 April 2022 .