vendredi 9 juin 2017

Mocking laravel contracts

I am using Laravel contracts in my application to decouple the application could from the framework code. Mainly though, I find it easier to see when a class is doing too much at a glance - our legacy projects suffered from 'hidden facades' being peppered all over the place.

use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\Factory as File;

class MyClass extends Command
{
    public function __construct(File $file)
    {
        $this->file = $file;
    }

    public function handle()
    {
        $this->file->put('/here.txt', 'stuff');
    }
}

The problem comes when trying to mock them. If I mock the contract an run the test, the mock is not used in place of the contract.

use Illuminate\Contracts\Filesystem\Factory as File

MyClassTest
{
    public function my_example_test()
    {
        $fileSystem = m::mock(File::class);
        $fileSystem->shouldReceive('put')->once();
        $this->app->instance(File::class, $fileSystem);

        $this->artisan('my-custom-command');
    }
}

When I inspect the $file property I can see of course that laravel used the concrete implementation (obviously). Except when I try and mock the concrete implementation, it too is used instead of the mock.

use Illuminate\Config\Repository as File;

MyClassTest
{
    public function my_example_test()
    {
        $fileSystem = m::mock(File::class);
        $fileSystem->shouldReceive('put')->once();
        $this->app->instance(File::class, $fileSystem);

        $this->artisan('my-custom-command');
    }
}

I tried mocking both but this doesn't work either. I am doing integration tests hence why I am calling the command using artisan. Apparantly there is a slightly easier way for unit tests but this does not help in my situation.

Aucun commentaire:

Enregistrer un commentaire