While the package was - and still is - fully tested, the Laravel bridge i wrote didn’t have a single tests. I didn’t like that.
I didn’t want that to ruin my awesome code coverage0. So i added @codeCoverageIgnore to the files in the bridge package (namespace). There were 3 files in total - a ServiceProvider, a Facade and errm, a Manager.
In the spirit of modularity, I then decided to migrate the bridge to it’s own repository. Then the problem resurfaced. I wasn’t going to create a package without a testsuite. I just couldn’t entertain that thought.
That birthed this blog post.
The Blog Post itself
For the most part of integrating a package into Laravel, we need at least a Facade and a ServiceProvider. Extra classes can also be added. For example, Laravel’s Filesystem package defines extra objects. In the case of the migrated package as mentioned earlier, i had just 3 objects - a Facade, a ServiceProvider and a Manager.
As i said earlier, I wanted to be certain i was interacting correctly with Laravel ?. So how do i get that done ? There are actually two ways to do this :
Run the entire framework like end to end tests are being written.
Mock out what you need.
The first option is exactly the same reason i didn’t have a testsuite for the bridge while it lived in the core library. Well, another reason was because i didn’t want to have to specify laravel/framework as a dependency - require or require --dev. So i skipped this.
The second option makes a lot of sense since we have avoid all that bootstrapping and use only the part of the framework we need to communicate with. I ended up going with this option and is what would be described iin this post.
If the concepts of mocking are somewhat new to you, i wrote a primer on that, you might want to check that.
Since the GbowoManager makes use of the Application instance Laravel has to provide with all services already bounded and isn’t too coupled to Laravel, that seems like a nice place to start.
Prophet is a mocking framework that comes with PHPUnit. Mockery can also be used.
The most interesting parts are
We created a mock that can act as a replacement with prophesize(Application::class)after which we added some stubs to it.
We are faking that we have gbowo.amplifypay and gbowo.paystack as registered services in the container when we actually don’t. Same thing goes for config. This is because we aren’t bootstrapping the framework, hence we don’t get a real Laravel Application instance. Meaning we have to act as if it was a real Laravel instance running.
Great ? How about making sure that works ?
Running that should give us green but we still have a huge part of the manager that isn’t tested yet. It allows for extensibility and we haven’t tested that yet. It throws exceptions when it couldn’t resolve an adapter by a name. Let’s put those in our test.
With the above tests, we are certain that the Manager would work as expected if it gets into a real Laravel application. And that is the type of confidence i like to have with my codebase.
While this is enough to build confidence that the package works as expected since the Facade and ServiceProvider are heavily dependent on Laravel - and their workings are actually implemented in Laravel. We can push the tests a bit harder by testing the Facade.
We can decide to leave this out as the Manager tests already confirms our trust in the package doing it’s thing
Here, we are eseentially making sure the Facade resolves to the GbowoManager. The message passing is done by Laravel, so we can leave that out trusting Laravel to work as expected.
As said alone, i am not interested in testing the service provider as that is too Laravel tied and even if i do, it would have ended up as a useless test and i don’t feel the need to get to a 100% coverage.