Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking Laravel controller dependency

In my Laravel app I have a controller with a method to show a particular resource. E.g. say the url is /widgets/26 My controller method might work like so:

Class WidgetsController {
    protected $widgets;

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

    public function show($id)
    {
        $widget = $this->widgets->find($id);

        return view('widgets.show')->with(compact('widget'));
    }
}

As we can see my WidgetsController has a WidgetsRepository dependency. In a unit test for the show method, how can I mock this dependency so that I don't actually have to call the repository and instead just return a hard-coded widget?

Unit test start:

function test_it_shows_a_single_widget()
{
    // how can I tell the WidgetsController to be instaniated with a mocked WidgetRepository?
    $response = $this->action('GET', 'WidgetsController@show', ['id' => 1]);

    // somehow mock the call to the repository's `find()` method and give a hard-coded return value
    // continue with assertions
}
like image 941
harryg Avatar asked Jul 30 '15 10:07

harryg


2 Answers

You can mock the repository class and load it into the IoC container.

So when Laravel gets to your controller, it will find it already in there and will resolve your mock instead of instantiating a new one.

function test_it_shows_a_single_widget()
{
    // mock the repository
    $repository = Mockery::mock(WidgetRepository::class);
    $repository->shouldReceive('find')
        ->with(1)
        ->once()
        ->andReturn(new Widget([]));

    // load the mock into the IoC container
    $this->app->instance(WidgetRepository::class, $repository);

    // when making your call, your controller will use your mock
    $response = $this->action('GET', 'WidgetsController@show', ['id' => 1]);

    // continue with assertions
    // ...
}

A similar setup has been tested and working fine in Laravel 5.3.21.

like image 177
Barnabas Kecskes Avatar answered Oct 12 '22 22:10

Barnabas Kecskes


There was a similar question on Laracasts. The person had something like this ( https://laracasts.com/discuss/channels/general-discussion/mockery-error?page=1 ) :

public function testMe()
{
    // Arrange
    $classContext = Mockery::mock('\FullNamespace\To\Class');
    $classContext->shouldReceive('id')->andReturn(99);
    $resources = new ResourcesRepo($classContext);

    // Act

   // Assert
}

You could however put this as well on the setUp method if using PHPUnit method ( http://docs.mockery.io/en/latest/reference/phpunit_integration.html ).

Hope this is helpful.

like image 33
vitorf7 Avatar answered Oct 13 '22 00:10

vitorf7