Skip to content
Advertisement

How to mock Eloquent Model in Laravel 8 when calling a route in PHPUnit

I’m trying to mock a method in the Model so that I am able to test the controller api endpoint with different scenarios.

I am currently using Laravel 8 with PhpUnit and Mockery package. In the route I am using Route model binding.

api.php

Route::get('/api/{project}', [ProjectController::class, 'show']);

ProjectController.php

class ProjectController extends Controller 
{
    public function show(Project $project)
    {
        $state = $project->getState();
        
        return response()->json($state);
    }
}

ProjectControllerTest.php

class ProjectControllerTest extends TestCase
{
    /**
     * @test
     * @group ProjectController
     */
    public function shouldReturn200ForValidProjectGuid()
    {
        $project = Project::factory()->create();

        $mock = Mockery::mock(Project::class);

        // I have also tried this, see error below
        // $mock = Mockery::mock(Project::class)->makePartial();

        $this->app->instance(Project::class, $mock);

        $mock->shouldReceive('getState')->andReturn('New South Wales');

        $response = $this->getJson("/api/{$project->guid}");
        
        $response->assertStatus(200)
            ->assertJson([
                'data' => 'New South Wales'
            ]);
     }
}

I am currently getting this error

Received Mockery_0_App_Models_Project::resolveRouteBinding(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code@924

I have tried other options like makePartial() instead, however it results in the following error as well

Received Mockery_0_App_Models_Project::__construct(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code@924

Any help would be much appreciated, thank you

Advertisement

Answer

You can try the following. I have changed the controller response slightly to make it work with assertJson().

web.php

Route::get('/projects/{project}', [ProjectController::class, 'show']);

ProjectController

<?php

namespace AppHttpControllers;

use AppModelsProject;

class ProjectController extends Controller
{
    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return IlluminateHttpResponse
     */
    public function show(Project $project)
    {
        return response()->json([
            'state' => $project->getState()
        ]);
    }
}

ProjectControllerTest

<?php

namespace TestsFeature;

use AppModelsProject;
use Mockery;
use TestsTestCase;

class ProjectControllerTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function test_example()
    {   
        $mock = Mockery::mock(Project::class)->makePartial();

        $mock->shouldReceive('resolveRouteBinding')->andReturnSelf();
        $mock->shouldReceive('getState')->andReturn('NSW');

        $this->app->instance(Project::class, $mock);

        $response = $this->get('/projects/1');

        $response->assertStatus(200)
            ->assertJson([
                'state' => 'NSW'
            ]);
    }
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement