使用PHPUnit测试PHP标头


97

我正在尝试使用PHPunit测试一个输出一些自定义标头的类。

问题是在我的机器上是这样的:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        $headers_list = headers_list();
        header_remove();

        ob_clean();

        $this->assertContains('Location: foo', $headers_list);
    }
}

甚至这个:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        header_remove();

        ob_clean();
    }
}

返回此错误:

name@host [~/test]# phpunit --verbose HeadersTest.php 
PHPUnit 3.6.10 by Sebastian Bergmann.

E

Time: 0 seconds, Memory: 2.25Mb

There was 1 error:

1) HeadersTest::testHeaders
Cannot modify header information - headers already sent by (output started at /usr/local/lib/php/PHPUnit/Util/Printer.php:173)

/test/HeadersTest.php:9

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.

即使没有包含其他文件,并且在PHP标记开始之前也没有其他字符,这似乎在测试运行之前向终端输出了其他内容。可能是PHPunit内部的某种原因导致了这种情况吗?

可能是什么问题?


14
如果还有其他人对此感兴趣,也只是想涵盖一下。headers_list()在运行PHPunit(使用PHP CLI)时不起作用,但是xdebug_get_headers()起作用。
titel 2012年

Answers:


123

问题是PHPUnit将在屏幕上显示标题,此时您不能添加更多标题。

解决方法是在隔离的过程中运行测试。这是一个例子

<?php

class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testBar()
    {
        header('Location : http://foo.com');
    }
}

这将导致:

$ phpunit FooTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 1 second, Memory: 9.00Mb

OK (1 test, 0 assertions)

关键是@runInSeparateProcess批注。

如果您使用的是PHPUnit〜4.1之类的东西,则会收到错误消息:

PHP Fatal error:  Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in -:378
Stack trace:
#0 {main}
  thrown in - on line 378

Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378

Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378

Call Stack:
    0.0013     582512   1. {main}() -:0

尝试将其添加到您的引导文件中以对其进行修复:

<?php
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
    define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php');
}

7
这会在某些define()语句PHPUnit_Framework_Exception中引起错误:注意:常量xyz已定义
Minhaz 2014年

1
@mebjas听起来无关紧要。
SamHennessy 2014年

4
应用时,我得到了这一点:PHP Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SplFileInfo' is not allowed' in phar:///usr/local/bin/phpunit/phpunit/Util/GlobalState.php:211
t1gor

2
这绝对是解决问题的最佳选择。它就像一个魅力!
xarlymg89

2
我必须使用xdebug_get_headers()来获取设置标头的数组。在我的情况下,headers_list()全局函数不起作用。
Shalom Sam

107

尽管在单独的过程中运行测试确实可以解决问题,但是在运行大量测试时仍有明显的开销。

我的解决方法是将phpunit的输出定向到stderr,如下所示:

phpunit --stderr <options>

那应该可以解决问题,并且这也意味着您不必创建包装函数并替换代码中的所有匹配项。


3
辉煌!我的代码没有更改,没有单独的过程,并且可以正常工作。
alexfernandez 2012年

但是我仍然会看到我犯的错误并得到error_reporting(E_ALL)的输出吗?
spankmaster79 2013年

1
@ spankmaster79是的,它只会转到您终端的标准错误。默认情况下,大多数终端将一起打印标准输出和标准错误,但实际上它们是独立的流。
乔恩·凯恩斯

我正在变得!!! tnx这个技巧,确实有道理,错误应该报告给stderror !!!Tnx
th3n3rd 2013年

42
您可以添加stderr="true"phpunit.xml来保存一些按键。
tszming 2014年

9

顺便说一句:对我来说,headers_list()一直返回0个元素。我注意到@titel对这个问题的评论,并认为这里值得特别提及:

如果还有其他人对此感兴趣,也只是想涵盖一下。headers_list()在运行PHPunit(使用PHP CLI)时不起作用,而是xdebug_get_headers()起作用。

高温超导


4

正如评论中已经提到的,我认为这是在XML配置文件中定义processIsolation的更好解决方案,例如

     <?xml version="1.0" encoding="UTF-8"?>
     <phpunit
        processIsolation            = "true"
        // ... 
     >
     </phpunit>

这样,您不必传递--stderr选项,这可能会激怒您的同事。


4
仅针对需要它的测试定义它可能更好。为所有测试设置它只会使测试运行缓慢。

3

为了$_SESSION测试/包含的文件内使用,我有一个更彻底的解决方案。我在../PHPUnit/Utils/Printer.php编辑了一个PHPUnit文件,在命令“ print $ buffer”之前添加了一个。"session_start();"

它对我来说就像一种魅力。但是我认为“诚实”用户的解决方案是迄今为止最好的解决方案。


您是否在存储库中提交了请求请求?我想这可能是一个普遍的问题。
t1gor

感谢您的提示,我在我的phpunit bootstrap.php中调用了session_start(),它对我有用
碰碰箱

0

@runInSeparateProcess的替代解决方案是在运行PHPUnit时指定--process-isolation选项:

name@host [~/test]# phpunit --process-isolation HeadersTest.php

这类似于在phpunit.xml中设置processIsolation =“ true”选项。

此解决方案与指定--stderr选项具有类似的优点/缺点,但是在我的情况下不起作用。基本上,不需要更改任何代码,即使由于在单独的PHP进程中运行每个测试可能会导致性能下降。


这可能是追踪原因并进行一些测试的第一步,但是为了创建可维护的测试,只需将注释直接嵌入到测试文件中即可。从命令行需要的“特殊”选项越少,CI系统配置的维护就越容易。

谁曾降级#失败。此答案是正确的另一选择。
fb

0

测试后,请使用--stderr参数从PHPUnit获取标头。

phpunit --stderr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.