Laravel Mocking在控制器内部进行接口

时间:2018-01-29 23:15:04

标签: laravel laravel-5 phpunit mockery

我正在尝试为我的控制器编写一些单元测试。

我已经实现了一个接口和存储库,它通过Dependancy Injection

传递给控制器

我编写了一个模拟界面的单元测试,New编写了一个控制器实例。

我的测试正在下降,出现以下错误

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

最终我想检查当控制器上调用索引方法时,然后它与接口正确交互,因此希望模拟它。我将编写进一步的测试来实际测试接口实现。

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);
    }
}
?>

更新

我已根据以下评论修改了我的测试,但现在失败了以下

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

我正在尝试的测试是

鉴于我要求场地 当我访问场地网址时 然后调用find方法 并且返回2。

<?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());
    }

}

**更新2 **

我现在已经更改了测试以遵循建议的内容,现在正在运行。奇怪的是,如果没有断言等于最后它将无法工作。

**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);
    }**

1 个答案:

答案 0 :(得分:0)

不确定要测试的是什么。

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

此行声明模拟的VenueRepositoryInterface对象的find()函数将被调用一次,并覆盖函数的行为

然后两次调用,

   $venueController->index();

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

导致测试失败。

第二个断言是不必要的,因为你只是提前断言结果,所以无论如何它都会通过。

此外,这不是一个好的测试,因为您正在测试函数的实现而不是函数的结果

<强>更新

根据this question,似乎你不能像这样链接声明,所以你需要改变

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

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