20

I'm testing a suite of REST web services with PHPUnit. We're using output buffering in order to gzip-encode the responses. When I run a test for the service with PHPUnit, I'm getting the error:

Cannot modify header information - headers already sent by (output started at /home/dotcloud/php-env/share/php/PHPUnit/Util/Printer.php:172)

It's complaining at the point that my code echo's the output to the browser...

I was able to work around this temporarily by adding an ob_start() call at the top of the test class(es), but when I run multiple tests at once, I get this error again.

Any ideas?

rhuff
  • 722
  • 2
  • 8
  • 14
  • well probably there has been sent out something already before your `echo` but if you don't show any code, we will not be able to help you further than that – bart s Jan 04 '13 at 07:03
  • Thanks @bart, but if there were, the error message above would have referenced the place where that "something" was -- not where I'm finally echoing the response to the browser. I'm not echoing anything before the actual response - but PHPUnit is... – rhuff Jan 04 '13 at 07:15
  • also... added the @outputBuffering annotation, but it's not clear what exactly that does. And it had no effect. – rhuff Jan 04 '13 at 07:16
  • 8
    Found the answer here: http://stackoverflow.com/questions/9745080/test-php-headers-with-phpunit?rq=1 Must run tests in isolation. – rhuff Jan 04 '13 at 07:30
  • possible duplicate of [PHPUnit output with header exceptions (--stderr no result)](http://stackoverflow.com/questions/13875761/phpunit-output-with-header-exceptions-stderr-no-result) – cweiske Jan 07 '13 at 13:59
  • Process isolation is just a way around this problem. The problem is caused by something like whitespace after php closing tag ?> or code sends http headers header() – Zdenek Machek Apr 30 '15 at 11:40

2 Answers2

28

There are several options with different advantages and disadvantages:

  1. run the tests in separate processes with @runInSeparateProcess, as you already found out. Good: better test isolation, Bad: worse performance, does not work well with global constants
  2. use --stderr flag to direct PHPUnit output to STDERR. Good: tests work as expected without changes, Bad: feels like a dirty workaround, possibly problems with CI tools
  3. don't actually send headers. Either replace the classes that use header() with stubs or if this is not easily possible or you want to do a full functional test, mock the header() function itself. More info on mocking built-in functions in this answer. Good: you can test the contents of the headers as well, your tests do rely less on global state Bad: You'll need to write more test code

I'd go for (3) and probably refactor the code as well to have a single class that's responsible for the headers and can be easily mocked.

Community
  • 1
  • 1
Fabian Schmengler
  • 24,155
  • 9
  • 79
  • 111
0

Here's an example for @fabian-schmengler 3rd option

class Response
    protected function header(string $header) : self
    {
        header($header);
        return $this;
    }
}

class MockResponse extends Response
{
    protected function header(string $header) : self
    {
        echo "header: {$header}\n";
        return $this;
    }
}
8ctopus
  • 2,617
  • 2
  • 18
  • 25