How to use mock objects in php testing

时间:2018-03-25 21:14:08

标签: php laravel testing phpunit

I'm trying to learn how to test properly and am struggling to get my head around mocks in the scenario below. I don't seem to be able to mock a class.

The main class uses a number of component classes to build a particular activity. I can test the component on it's own and mock it correctly but when I try to integrate test within the main class it calls the real service not the mock service.

This is in a Laravel 5.5 app.

I have a base class:

class booking {

private $calEventCreator

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

This is then extended by another class:

class EventType extends booking {

    //do stuff
}

The CalenderEventCreator relies on an external service which I want to mock.

class CalendarEventCreator {

    public function  __construct(ExternalService $externalService) {

        $this->externalService = $externalService;

    }
}

In my test I have tried to do the following:

public function test_complete_golf_booking_is_created_no_ticket()
{

    $this->booking = \App::make(\App\Booking\EventType::class);

    $calendarMock = \Mockery::mock(ExternalService::class);

    $calendarMock->shouldReceive([
        'create' => 'return value 1',
    ])->once();

    $this->booking->handle($this->attributes, 'booking');

}

But in trying to execute the test it's clear the ExyernalService is not using the mocked object.

I have tried re-arranging the code as follows:

$calendarMock = \Mockery::mock(Event::class);
    $calendarMock->shouldReceive([
        'create' => 'return value 1',
    ])->once();

    $this->booking = \App::make(\App\Booking\EventType::class);

    $this->booking->handle($this->attributes, 'booking');
}

and tried:

$this->booking = \App::make(\App\Booking\EventType::class, ['eventService'=>$calendarMock]);

But on each occassion the real service is called not the mock version

I'm learning this so apologies about fundamental errors but can someone explain how I should mock the external service correctly

1 个答案:

答案 0 :(得分:1)

也许有更好的方法来实现这一目标,但我使用以下方法:

$calendarMock = \Mockery::mock(ExternalService::class);
$calendarMock->shouldReceive([
    'create' => 'return value 1',
])->once();

$this->booking = new \App\Booking\EventType($calendarMock);
$this->booking->handle($this->attributes, 'booking');

我没有使用服务容器来解析类,而是直接调用构造函数来传递模拟服务。

<强>更新

寻找其他方法,我找到this answer。使用该解决方案,您的代码将如下所示:

$calendarMock = \Mockery::mock(ExternalService::class);
$calendarMock->shouldReceive([
    'create' => 'return value 1',
])->once();
$this->app->instance(ExternalService::class, $mock);

$this->booking = \App::make(\App\Booking\EventType::class);
$this->booking->handle($this->attributes, 'booking');