【问题标题】:Laravel Mocking interfaces inside controllers控制器内部的 Laravel 模拟接口
【发布时间】:2018-07-08 18:08:07
【问题描述】:

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

我已经实现了一个接口和存储库,这是通过依赖注入传递给控制器​​的

我编写了一个模拟接口的单元测试,并新建了一个控制器实例。

我的测试因以下错误而下降

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

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

场地控制器测试

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

更新

我已经根据下面的 cmets 修改了我的测试,但是现在失败了

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

【问题讨论】:

    标签: laravel laravel-5 phpunit mockery


    【解决方案1】:

    不确定您要测试什么。

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

    【讨论】:

    • 我已根据您的 cmets 更新了测试以使其更有效,我已将更新包含在主帖子中,但它不起作用。但我理解你所说的测试没有测试正确的东西
    猜你喜欢
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 2013-04-27
    • 1970-01-01
    相关资源
    最近更新 更多