Search code examples
phpphpunitlaravellaravel-4mockery

Laravel 4 Unit Testing: "headers already sent" error when injecting mocks using App::instance


I'm new to Laravel and the concept of the IoC. I was following the great tutorials over a Nettuts (http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/) and was able to successful test my controller. However I wanted to isolate the controller by mocking the database. As soon as I attempted to inject my mocked object into the IoC I get the following error:

Cannot modify header information - headers already sent by (output started at /Users/STRATTON/Dev/SafeHaven/vendor/phpunit/phpunit/PHPUnit/Util/Printer.php:172)

The line it's referring to outputs PHPUnit's buffer using the 'print' construct. Something is causing output to be sent before headers are set but I can't track down the problem.

I'm able to run all my tests successfully when the controller calls the real model and makes the database call. At the same time I'm able to mock the object successfully and exercise mock without error. But as soon as I attempt to inject the mocked object using App::instance() the error appears.

I've also tested this with PHPUnit's mocks and get the same results. Am I mocking the object properly? Do I have a problem with namespacing? Am I missing something that's outputting content?

Controller:

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

}

TestCase

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

}

Solution

  • It actually a a bug on how exception is handled during running test case, this however has been fixed, just run composer update.