CakePHP测试:无法修改标头信息 - 已经发送的标头

时间:2013-09-27 04:01:05

标签: php cakephp testing header phpunit

注意:这不是一个重复的问题。我见过一些类似的问题,但我问的是单元测试。

我正在尝试使用CakePHP 2.3.6编写测试用例,并且遇到使用header()函数的测试用例的问题。测试从浏览器运行没有问题,但是从命令行,我得到以下错误。

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

例如,我的代码中的以下行发生错误。

header( 'Content-Type: application/json; charset=utf-8' );

对于PHPUnit,可以使用@runInSeparateProcess来避免这种情况,但在CakePHP中,它会导致以下错误。

Notice: Constant TIME_START already defined in /app/lib/Cake/bootstrap.php on line 22
Notice: Constant CAKE already defined in /app/lib/Cake/bootstrap.php on line 48
Notice: Constant APPLIBS already defined in /app/lib/Cake/bootstrap.php on line 60
Notice: Constant SECOND already defined in /app/lib/Cake/basics.php on line 26
Notice: Constant MINUTE already defined in /app/lib/Cake/basics.php on line 27

等等。

我被困住了。有谁知道如何处理这个? 非常感谢。

5 个答案:

答案 0 :(得分:3)

检查你是否在标题行之前提供任何输出,通常是回声,也许你在标题行之前回显了一些html

答案 1 :(得分:1)

关于“已发送标题”的问题的所有其他答案都是正确的,但在您的情况下,它是某种专业。你不能逃避这种情况,因为PHPUnit会在运行到你试图发送标题的代码之前发送输出。

但关键是:你不应该使用header()函数。您应该使用CakeResponse对象。我的快速谷歌搜索发现了这个(显然是2.0,所以你应该找到更新的文档版本):http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse

如果使用此对象,整个测试过程可以避免在测试执行期间调用header(),因为您可以注入这样的模拟对象:http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse-and-testing

最后,如果您想顺利运行测试,以下基本规则适用于您的代码:

  • 不要调用任何依赖于某种情况的PHP函数(比如headers()取决于先没有echo)或改变那种情况
  • 不要调用需要测试的PHP函数(例如“必须调用error_log”)

所有这些函数调用都应该包装在一个可以模拟的对象中。

答案 2 :(得分:1)

你一定误解了单位测试实际上是什么。所以请注意,你没有使用错误的工具。

例如,在您的问题中写道:

  

例如,我的代码中的以下行发生错误。

header( 'Content-Type: application/json; charset=utf-8' );

这行代码不是可以使用PHPUnit测试的某些代码行。不要尝试在Phpunit测试中运行此类代码,总是在这里遇到问题。

所以你写得正确,你被卡住了,我完全可以理解。然而,这也取决于观点。有些问题有一个非常明显的解决方案:不要这样做。而是使用正确的工具来测试,例如通过HTTP协议访问应用程序的功能测试,以便他们可以测试HTTP响应头。 PHPUnit不能 - 我不应该在这里说:至少不是你使用它的方式(我假设你想使用它)。

如果这不是一个选项,关于标题错误的规范问题概述了如何处理该错误的许多方法,建议输出控制函数可能对您的测试有用:

该答案还应告诉您从PHP发送标题时需要了解的任何内容,以便更好地了解您所测试的系统。

答案 3 :(得分:0)

在发送标题之前不应该发出任何输出!

必须在进行任何输出之前调用发送/修改HTTP标头的函数。否则呼叫失败。查找输出到屏幕或任何打印或回显语句的任何错误。

请参阅已接受的答案here

答案 4 :(得分:0)

问题是,你的方法不对! PHPUnit应该进行UNIT测试,但你要做的是更多的行为测试,可以使用Behat / Mink测试来完成。

如果您要使用单元测试,那么您必须解耦系统的单元并按单元进行单元测试,如果是重定向,您可以使用模型来捕获重定向功能并对其进行适当的检查。