14

I have this strange problem when i call the parent::setUp() on my TestCase class for unit test a class when i run phpunit it throw me this error:

1) MatchRequestRepositoryTest::test_find_requests_by_match_id ErrorException: session_start(): Cannot send session cookie - headers already sent by (output started at /var/www/project.dev/vendor/phpunit/phpunit/PHPUnit/TextUI/TestRunner.php:459)

What can be the problem? Thanks for any help.

Fabrizio Fenoglio
  • 5,767
  • 14
  • 38
  • 75
  • 2
    Please check this : http://stackoverflow.com/questions/8028957/how-to-fix-headers-already-sent-error-in-php – Goku Apr 24 '14 at 13:40
  • You'll have to share the contents of your test. Also, is your application doing any direct manipulation of sessions, either via native `session_` function calls or `Session::`? – Andreas Apr 25 '14 at 11:25
  • Possible duplicate of [Test PHP headers with PHPunit](http://stackoverflow.com/questions/9745080/test-php-headers-with-phpunit) – Jeff Puckett Jun 27 '16 at 03:20

4 Answers4

33

One way to handle this in PHPUnit is to send output to stderr instead of stdout as is demonstrated by this answer.

phpunit --stderr

Or by adding stderr="true" in your phpunit.xml as is pointed out in this comment.

Jeff Puckett
  • 37,464
  • 17
  • 118
  • 167
27

(UPDATE: Thanks to comment by Louis Charette, this will only work in php 7.1 and earlier (and reading the bug report, it sounds like a regression they don't intend to fix. The better solution is therefore Jeff Puckett's (https://stackoverflow.com/a/38045422/841830), of giving the --stderr flag on the commandline to phpunit. This keeps stdout for your code, stderr for phpunit, and so they don't clash.)


The problem is that you have some code, perhaps deep in the framework you use, that calls session_start(). That, in turn, wants to send a cookie. But PHPUnit has already started writing output to stdout.

The point to understand here is that this is just a unit test, no-one cares about the header. So just suppress the error message. And the way you do that, without altering the system-under-test, is to call session_start() in your own unit test (either before parent::setUp() or inside that setUp function). And use the @ prefix to suppress errors. e.g.

function setUp() {
  @session_start();
  parent::setUp();
  ...
}
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • 2
    Unfortunately, this solution will still produce an error for your test. It will produce something like this: `There was 1 error: 1) Classname::ClassTest A session had already been started - ignoring session_start()` – w00tland Jan 07 '16 at 10:51
  • 1
    @w00tland The `@` should stop any errors or warnings being reported. Do you have the `@` on the line it is complaining about? And does adding/removing the `@` change the error message? (If you cannot get the message to go away, it might be worth starting a new question; this one was about how to get rid of the "headers already sent" complaint.) – Darren Cook Jan 07 '16 at 11:02
  • 3
    I know it should prevent warnings from being reported. The message I shared above is the result of suppressing the message. And yes, I get the `Cannot send session cookie - headers already sent by` message if I remove the @. And I have the exact same problem; I'm just trying to get rid of the "headers already sent" message. – w00tland Jan 25 '16 at 08:54
  • 2
    For people finding this though Google, this fix might produce another set of errors with PHP 7.2 in relation with `session_set_save_handler`. See : https://bugs.php.net/bug.php?id=75628 Jeff Puckett answer is a better solution in relation to PHP 7.2 change. – Louis Charette Oct 25 '18 at 00:07
  • @LouisCharette Thanks. I've updated the answer with that info. – Darren Cook Oct 25 '18 at 05:53
4
 /**
 * @test
 * @runInSeparateProcess
 */
public function testName(){
    //... your test
}
  • 1
    Please add a comment, explaining your answer. – baikho Oct 14 '20 at 21:14
  • 1
    @baikho this code is pretty much selfexplaining. It lets the test run in a seperate process so the headers are not already sent by phpunit. – NiMeDia Jun 09 '21 at 05:56
1

In Laravel I avoided the issue by checking the environment and avoiding problematic code for 'testing' environment.

// Code working in Laravel 4.2
if(App::environment() != 'testing') {
        // this will be skipped when testing
        setcookie('key', $val, time() + (86400 * 999), '/');
}

NOTE - Warning: this means you cannot test this piece of code!