3

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 Answer 1

3

Maybe there is a better way to achieve this but I'm using the following approach:

$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');

Instead of using the service container to resolve the class, I call the constructor directly passing the mocked service.

UPDATE

Looking for other ways to do that, I found this answer. Using that solution, your code would look like this:

$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');
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you - that has done the trick and the mock is being used as expected. Brilliant!!! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.