Warning: This article was written in 2019, the content might be out of date.

When you have a test that uses a class that pull data from an external API, it might be a good idea to mock this object so it does not reach anywhere outside of your local development or your CI service provider, and you can assure you are getting the data you are expecting.

Let's use the simple example provided by Mockery.

class Temperature
{
    private $service;

    public function __construct($service)
    {
        $this->service = $service;
    }

    public function average()
    {
        $total = 0;
        for ($i=0; $i<3; $i++) {
            $total += $this->service->readTemp();
        }
        return $total/3;
    }
}

You need to test the $service. However, this $service class calls an external API when you call readTemp(), we can use Mockery to bypass that when running test in Laravel.

According to Laravel Mocking, in 5.8, you can do the following

use App\Service;

$service = $this->mock(Service::class, function ($mock) {
    $mock->shouldReceive('readTemp')->times(3)->andReturns(10, 12, 14);
});

So, in your test, you can do the following:

public function TemperatureAverageTest()
{
    $service = $this->mock(Service::class, function ($mock) {
        $mock->shouldReceive('readTemp')->times(3)->andReturns(10, 12, 14);  
    });

    $temperature = new Temperature($service);
    $this->assertEquals(12, $temperature->average());
}

When I first use Mockery in 5.8, I was stumbleupon on why after running $this->mock(...) the object does not create a mock. That's when I find out it actually returns a mock object not overriding automatically all Service, I actually have to use it and apply it in my code.

Next | Previous