PhpStorm、PHPUnit和setcookie

PhpStorm、PHPUnit和setcookie,php,phpunit,phpstorm,Php,Phpunit,Phpstorm,我试图在一个非常好的IDE PhpStorm中使用setcookie()函数进行一些单元测试。但每次我都会遇到以下错误: Cannot modify header information - headers already sent by (output started at /tmp/phpunit.php:418) 此错误的原因可能是在调用setcookie()之前使用flush()打印('some text')。但是刷新是在PhpStorm生成的/tmp/phpunit.php文件中执行

我试图在一个非常好的IDE PhpStorm中使用setcookie()函数进行一些单元测试。但每次我都会遇到以下错误:

Cannot modify header information - headers already sent by (output started at /tmp/phpunit.php:418)
此错误的原因可能是在调用setcookie()之前使用flush()打印('some text')。但是刷新是在PhpStorm生成的/tmp/phpunit.php文件中执行的。而setcookie()是从我的源代码调用的。因此,我无法编辑生成的文件来执行某种输出缓冲。还有另外一个时刻:PhpStorm执行/tmp/phpunit.php脚本,如下所示:

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

请帮助我解决这个问题。如何直接从PhpStorm运行单元测试?

一种可能的解决方法是使用“mock”替换
setcookie()
函数

这是单元测试中的一种常见技术,在单元测试中,您希望测试依赖于外部类或函数的东西,而您不想影响当前的测试

方法是在单元测试代码中为
setcookie()
创建存根函数定义。然后在测试期间调用该函数,而不是真正的
setcookie()
函数。具体如何实现这个存根函数取决于您自己,并且取决于您的代码使用它的目的

这种方法的主要问题是,默认情况下,PHP不允许覆盖现有函数——如果在标准PHP安装上尝试这种方法,将得到“错误:无法重新声明函数”

这个问题的解决方案是PHP,它是专门为这种测试设计的,并且允许您进行测试,包括内置测试

如果您在测试环境中配置PHP安装以包含Runkit扩展,那么您将能够进行此类测试


希望有帮助。

我找到了一个更简单的解决方案。考虑这个类:

class Cookie
{
    public function set($name, $value)
    {
        return setcookie($name, $value);
    }
}
除非设置注释,否则测试将抛出问题中描述的错误


而不是试图设置实际的cookie头(因为内容已经发送,所以会失败);出于测试目的,您只需显式设置COOKIE超全局:

$_COOKIE['mycookie']=myvalue';

在不创建代理类和模拟代理类的情况下,可以使用另一种变通方法,但需要在工作代码级别进行更改

function setTestableCookie(string $key, $value): void
{
    $_COOKIE[$key] = $value;

    if (headers_sent() === false) {
        setcookie(
          $key,
          $value,
          ... other cookie params ...
        );
    }
}

这样,它将在单元测试中工作,并在生产代码上设置正确的cookie参数。

非常感谢您的回答,Spudley!这真是个好主意。我将很快在我的测试环境中尝试Runkit。如果您不想或不能使用Runkit(即使您可以),我建议创建一个封装所有cookie操作的类。然后,您可以为该类创建一个模拟对象,以避免完全调用
setcookie()
。谢谢您的回答,David!看来你的观点更适用。但是我已经成功地通过重新定义
setcookie()
实现了Runkit():
Runkit\u函数\u重新定义('setcookie','name,$value=null,$expire=null,$path=null,$domain=null,$secure=null,$httponly=null','')我使用的可能重复项如下:phpunit——使用setcookie时工作的stderr。测试将失败,因为
Cookie::set
返回void。@JohnLinhart这只是抑制错误,但该值实际上没有在(单独的进程)中设置。因此,您不能测试代码并断言$\u COOKIE['mycookie']=='myvalue'。您将得到一个未定义的索引错误。由于它不是一个有效的解决方案,所以对此进行了否决,但现在无法撤消。事实上,现在结合
@runinsepareprocess
注释,这对我来说很有效。否则仍会弹出“header ready sent”错误。
function setTestableCookie(string $key, $value): void
{
    $_COOKIE[$key] = $value;

    if (headers_sent() === false) {
        setcookie(
          $key,
          $value,
          ... other cookie params ...
        );
    }
}