尝试使用 IoC 容器在我的控制器测试中交换模型,但对象不是交换器

Trying to swap a model in my controller test with IoC Container, but object not swapper

我正在尝试使用 IoC 容器在测试时换出我的问题模型。虽然我已经创建了一个模拟模型,并在我的测试期间使用 App::instance() 尝试交换依赖关系,但我可以从 var_dump 中看到它不起作用。我的代码有什么问题?

<?php

class QuestionsControllerTest extends TestCase {

    protected $mock;

    public function __construct()
    {
        // This is how Net tuts tutorial instructed, but 
        // I got Eloquent not found errors
        // $this->mock = Mockery::mock('Eloquent', 'Question');

        // so I tried this instead, and it created the mock
        $this->mock = Mockery::mock('App\Question'); 
    }

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

    public function testQuestionIndex()
    {
        // var_dump(get_class($this->mock)); exit; // outputs: Mockery_0_App_Question
        // var_dump(get_class($this->app)); exit; // outputs: Illuminate\Foundation\Application

       $this->mock
           ->shouldReceive('latest')
           ->once()
           ->andReturnSelf();

        $this->mock
            ->shouldReceive('get') //EDIT: should be get
            ->once()
            ->andReturn('foo');

    $this->app->instance('App\Question', $this->mock);


        // dispatch route

        $response = $this->call('GET', 'questions');

        $this->assertEquals(200, $response->getStatusCode());
    }
}

到目前为止还好吗?下面是我的问题控制器:

class QuestionsController extends Controller {

    protected $question;

    public function index(Question $question)
    {
        // var_dump(get_class($question)); exit; // Outputs App\Question when testing too

        $questions = $question
            ->latest()
            ->get();

        return view('questions.index', compact('questions'));
    }
    ...

因此,如果不交换对象,无论如何它都不会注册对方法的调用:

Mockery\Exception\InvalidCountException: Method latest() from Mockery_0_App_Question should be called
 exactly 1 times but called 0 times.

顺便说一下,我已经安装了 Mockery ~0.9、Laravel 5.0 和 PHPUnit ~4.0。非常感谢对此的任何帮助。

您收到此错误是因为您没有完全定义模拟。

你告诉你的 mock 它应该期望 latest 被调用一次,但你没有指定最近应该 return。在控制器的下一行调用 get.

试试下面的代码

    $this->mock
       ->shouldReceive('latest')
       ->once()
       ->andReturnSelf();


     $this->mock
       ->shouldReceive('get') //EDIT: should be get
       ->once()
       ->andReturn('foo');

    $this->app->instance('Question', $this->mock);

关于在 larvel 中测试控制器的非常好的文章 http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456

我认为您在使用 instance() 时需要指定完整的命名空间。 Laravel 否则将假定模型位于全局命名空间 ('\Question') 中。

这应该有效:

$this->app->instance('App\Question', $this->mock);

现在关于另一个问题,你的模拟。既然你的观点想要一个集合,为什么不给它一个呢?如果你不想测试视图,你可以简单地实例化一个空集合并且 return that:

$this->mock
     ->shouldReceive('latest')
     ->once()
     ->andReturnSelf();

$this->mock
     ->shouldReceive('get')
     ->once()
     ->andReturn(new Illuminate\Database\Eloquent\Collection);

如果需要,您还可以检查视图是否已正确接收变量:

$response = $this->call('GET', 'questions');

$this->assertViewHas('questions');