Laravel 4单元测试:使用App :: instance注入模拟时“已发送标头”错误

时间:2013-05-17 18:06:37

标签: php phpunit laravel laravel-4 mockery

我是Laravel的新手,也是IoC的概念。我正在通过Nettuts(http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/)完成了很棒的教程,并且能够成功测试我的控制器。但是我想通过模拟数据库来隔离控制器。一旦我试图将我的模拟对象注入IoC,我就会收到以下错误:

  

无法修改标题信息 - 已经发送的标题(输出从/Users/STRATTON/Dev/SafeHaven/vendor/phpunit/phpunit/PHPUnit/Util/Printer.php:172开始)

它引用的行使用'print'构造输出PHPUnit的缓冲区。有些事情导致在设置标题之前发送输出但是我无法追踪问题。

当控制器调用真实模型并进行数据库调用时,我能够成功运行所有测试。同时我能够成功地模拟对象并且无错误地运行模拟。但是一旦我尝试使用App :: instance()注入模拟对象,就会出现错误。

我也用PHPUnit的模拟测试了这个并得到了相同的结果。我是否正确地嘲笑对象?我对命名空间有问题吗?我错过了输出内容的东西吗?

控制器:

<?php namespace App\Controllers;

use App\Models\Repositories\ArticleRepositoryInterface;

class HomeController extends BaseController {

    protected $articles;

    public function __construct(ArticleRepositoryInterface $articles) 
    {
        $this->articles = $articles;
    }

    public function index()
    {
        $articles = $this->articles->recent();
        return \View::make('home.index')
            ->with('articles', $articles);
    }

}

测试用例

<?php namespace Tests\Controllers;

class HomeControllerTest extends \TestCase {

    public function testIndex()
    {
        $mocked = \Mockery::mock('App\\Models\\Repositories\\ArticleRepositoryInterface');
        $mocked->shouldReceive('recent')->once()->andReturn('foo');
        \App::instance('App\\Models\\Repositories\\ArticleRepositoryInterface', $mocked);
        //$mocked->recent();

        $this->call('GET', '/');
        $this->assertResponseOk();
        $this->assertViewHas('articles');
    }

}

2 个答案:

答案 0 :(得分:1)

它实际上是一个关于在运行测试用例期间如何处理异常的错误,但是这已经修复,只需运行composer update。

答案 1 :(得分:0)

回答我自己的问题 - 错误的原因是代码的某些部分导致PHP错误或异常被抛出。

在这种情况下,问题是从View中抛出异常。 View期望方法recent()返回的值是一个Eloquent Collection(Illuminate \ Database \ Eloquent \ Collection),或者至少是View可以迭代的东西。

HomeControllerTest :: TestIndex方法正在模拟对象,当调用recent()时,它返回'foo'。 View无法迭代字符串,因此会抛出异常。下面是两个解决方案,后者允许测试视图是否接收到正确的对象类型。

$mocked->shouldReceive('recent')
    ->once()
    ->andReturn([]);

如果您遇到类似的问题,请检查所有正在测试的代码,并确保您的测试实际上满足所有要求/依赖...或者使用TDD ...我应该从一开始就做的事情和避免了这个问题。