0

I am trying to write some unit tests for my controllers.

I have implemented an interface and repository, this is passed in to the controller via Dependancy Injection

I have written a unit test that mocks the interface and New's up an instance of a controller.

My test is falling with the following error

Mockery\Exception\InvalidCountException : Method find(<Any Arguments>) from Mockery_0_App_Interfaces_VenueRepositoryInterface should be called
 exactly 1 times but called 2 times.

Ultimately i want to check then when the index method is called on the controller, then it interacts correctly with the interface hence the desire to mock it. I will write further tests to actually test the interface implementation.

VenueControllerTest

<?php

namespace Tests\Unit;


use \Mockery;
use Tests\TestCase;
use App\Http\Controllers\VenueController;

class VenueControllerTest extends TestCase
{

protected $venueRepositoryInterface;

protected $mock;

    public function setUp()
    {
        parent::setUp();

            $this->mock = \Mockery::mock('App\Interfaces\VenueRepositoryInterface');
    }


    public function tearDown()
    {
        Mockery::close();
    }


    public function testControllerIndex()
    {

       $this->mock->shouldReceive('find')->once()->andReturn(2);
       $venueController = new VenueController($this->mock);
       $venueController->index();
       $this->assertEquals($this->mock->find(1),2);
    }

}

VenueController.php

  <?php

namespace App\Http\Controllers;

use App\Interfaces\VenueRepositoryInterface;
use Illuminate\Http\Request;

class VenueController extends Controller
{

protected $venueRepository;

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

    public function index()
    {
        $this->venueRepository->find(1);
        return view( 'venue');
    }

}

VenueRepositoryInterface.php

<?php
// app/Repositories/Contracts/VenueRepositoryInterface.php

namespace App\Interfaces;

interface VenueRepositoryInterface
{
    public function find($id);
    public function findBy($att, $column);
}

?>

VenueRepository.php

<?php
// app/Repositories/venueRepository.php
namespace App\Repositories;

use App\Interfaces\VenueRepositoryInterface;
use App\Venue;

class VenueRepository implements VenueRepositoryInterface
{
    protected $venue;

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

    public function find($id)
    {
        return 2;
    }

    public function findBy($att, $column)
    {
        return $this->venue->where($att, $column);
    }
}
?>

UPDATE

I have modified my test based on the below comments, but this is now failing with the following

Mockery\Exception\InvalidCountException : Method find(<Any Arguments>) from Mockery_0__VenueRepositoryInterface should be called
 exactly 1 times but called 0 times.

My test I am attempting is

Given I request the venue when i visit the venue url then the find method is invoked and 2 is returned.

<?php

namespace Tests\Unit;

use \Mockery;
use Tests\TestCase;


class VenueControllerTest extends TestCase
{

protected $venueRepositoryInterface;

protected $mock;

    public function setUp()
    {
        parent::setUp();

    }


    public function tearDown()
    {
        Mockery::close();
    }


    public function testControllerIndex()
    {

        $mock = Mockery::mock('VenueRepositoryInterface')->shouldReceive('find')->once()->andReturn(2);
        $this->app->instance('VenueRepositoryInterface',$mock);
        $response = $this->call('GET','venue');
        $this->assertEquals(200, $response->status());
    }

}

**UPDATE 2 **

I have now changed the test to follow what has been suggested, this is now working. Oddly it won't work without the assert equals at the end.

**public function testControllerIndex()
{
            $venue = new  Venue();
            $mock = Mockery::mock('App\Interfaces\VenueRepositoryInterface');
            $mock->shouldReceive('find')->once()->with(1)->andReturn($venue);
            $this->app->instance('App\Interfaces\VenueRepositoryInterface',$mock);
            $response =  $this->call('GET', 'venue');
            $this->assertEquals($response->getStatusCode(), 200);
    }**
Cœur
  • 37,241
  • 25
  • 195
  • 267
JaChNo
  • 1,493
  • 9
  • 28
  • 56

1 Answers1

0

not sure what you want to test.

$this->mock->shouldReceive('find')->once()->andReturn(2);

this line asserts the mocked VenueRepositoryInterface object's find() function will be called exactly once, and override the behaviour of the function

then it is called in twice,

   $venueController->index();

and

$this->assertEquals($this->mock->find(1),2);

which results in the test failing.

The second assertion is unnecessary, as you just assert the result early so it will pass anyway.

Also, this is not a good test, as you're testing the implementation of a function instead of the result of a function

UPDATE

according to this question, it seems you can't chain declaration like that, so you will need to change

$mock = Mockery::mock('VenueRepositoryInterface')->shouldReceive('find')->once()->andReturn(2);

to

$mock = Mockery::mock('VenueRepositoryInterface');
$mock->shouldReceive('find')->once()->andReturn(2);
cwang
  • 1,103
  • 11
  • 21
  • I have updated the test to be more effected as per your comments, i have included the update in the main post, it is not working. but i understand what you were said about the test not testing the right thing – JaChNo Jan 30 '18 at 09:25