I’m trying to write tests to assert that methods called in my AppServiceProvider boot method are present & enforced logic.
So far I’m using mocks & reflection, however I am having an issue with the DB::prohibitDestructiveCommands(app()->isProduction()) method call.
The method prohibitDestructiveCommands() isn’t on the underlying proxied class (DatabaseManager), it’s on the actual facade class.
This has made it quite difficult for me. I have spent far too long trying to solve this; to come up with a solution that will allow to assert that the facade method is called.
So I have landed on the following test as being a possible way to solve my issue:
test('Invokes DB::prohibitDestructiveCommands in production', function ()
{
$this->app->detectEnvironment(fn() => 'production');
$mock = mock('overload:IlluminateSupportFacadesDB');
$mock->shouldReceive('getFacadeRoot')
->once()
->andReturn(new DB);
$mock->shouldReceive('prohibitDestructiveCommands')
->once()
->with(true);
$this->provider->boot();
$mock->shouldHaveReceived('prohibitDestructiveCommands');
}
);
It still has the problem, that the Facade is already loaded in that namespace and can’t be overloaded, so it results in the test having the following error:
MockeryExceptionRuntimeException:
Could not load mock IlluminateSupportFacadesDB,
class already exists
at vendor/mockery/mockery/library/Mockery/Container.php:401
at vendor/mockery/mockery/library/Mockery.php:681
at vendor/mockery/mockery/library/helpers.php:40
If you can figure out how I can overcome this, or another way of asserting that a method from a principal facade class is invoked, then I would really appreciate the assistance.
Note: I know that I could wrap the method like so & mock the provider to assert the call of that method, however it’s not a wonderful solution to enforcing behaviour through tests, as the call to DB::prohibitDestructiveCommands(app()->isProduction()) could be removed or changed by a dev at a later time from the wrapping method & tests wouldn’t pickup the structural change.
I am also aware, I can test the outcome of the calling the prohibited commands, but this is a unit tests, and shouldn’t be cross testing behaviour like this, just the structure of the class.