Question

I'm trying to make some unit tests using a setcookie() function in a pretty good IDE PhpStorm. But I get a following error every time:

Cannot modify header information - headers already sent by (output started at /tmp/phpunit.php:418)

Probably the reason of this error is print('some text') with flush() before setcookie() calling. But flushing is performed in a /tmp/phpunit.php file generated by PhpStorm. While setcookie() is called from my sources. So I can't edit the generated file to do some kind of output buffering. Also there is some another moment: PhpStorm executes /tmp/phpunit.php script like this:

/usr/bin/php /tmp/phpunit.php -config /var/www/.../protected/tests/phpunit.xml d /var/www/.../protected/tests/unit/user

Please help me to workaround this issue. How can I run unit tests from PhpStorm directly?

Was it helpful?

Solution

One possible way around this is to use a 'mock' replacement for the setcookie() function.

This is a common technique in unit testing, where you want to test something that relies on an external class or function that you don't want to affect the current test.

The way to do it would be to create a stub function definition for setcookie() within you unit test code. This would then be called during the test instead of the real setcookie() function. Exactly how you implement this stub function is up to you, and would depend on what your code uses it for.

The major problem you'll have with this approach is that PHP doesn't allow you to override existing functions by default - if you try this on a standard PHP installation, you'll get "error: function cannot be redeclared".

The solution to this problem is PHP's Runkit extension, which is explicitly designed for this kind of testing, and allows you to rename an existing function, including built-in ones.

If you configure the PHP installation in your testing environment to include the Runkit extension, you will be able to do this kind of test.

Hope that helps.

OTHER TIPS

I found a simpler solution. Consider this class:

class Cookie
{
    public function set($name, $value)
    {
        return setcookie($name, $value);
    }
}

The test will throw the error described in the question unless you set the annotation @runInSeparateProcess

class CookieTest
{
    /**
     * @runInSeparateProcess
     */
    function test_set()
    {
        $cookie = new Cookie;
        $this->assertTrue($cookie->set('mycookie', 'myvalue');
    }
}

Instead of trying to set actual cookie headers (which will fail because content has already been sent); For test purposes, you may simply set the COOKIE superglobal explicitly:

$_COOKIE['mycookie']=myvalue';
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top