【问题标题】:CakePHP testing: Cannot modify header information - headers already sent byCakePHP 测试:无法修改标头信息 - 标头已由
【发布时间】:2013-10-03 06:17:26
【问题描述】:

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

我正在尝试使用 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

等等。

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

【问题讨论】:

  • 使用quite 选项php -q 防止标头进入标准输出。
  • 谢谢,但没用。
  • 那你做错了什么。即使运行php-cgi 而不是php-cliphp -q 也应该可以工作。

标签: php cakephp testing header phpunit


【解决方案1】:

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

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

查看接受的答案here

【讨论】:

  • 那个答案是关于一般情况,但我是在询问测试情况。我的函数在标题函数之前没有输出任何东西。但是在 CakePHP 测试中,测试是按顺序运行的,所以情况不同,我得到了错误。
【解决方案2】:

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

【讨论】:

  • 我没有在标题之前发送任何输出。如果有人发送,那一定是 CakePHP 测试单元。我正在寻找如何阻止这种情况。
【解决方案3】:

有关“已发送标头”的问题的所有其他答案都是正确的,但在您的情况下,这是某种专业。您无法摆脱这种情况,因为 PHPUnit 在运行到您尝试发送标头的代码之前会发送输出。

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

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

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

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

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

【讨论】:

  • 我明白了。不知何故 CakeResponse 在我的情况下不能很好地工作,所以我不得不为这个控制器使用 header() 函数。我认为像这样的一些控制器可能不适合单元测试。我会寻找解决方法或其他方式。
【解决方案4】:

您一定误解了单元测试实际上是什么。因此,请注意不要使用错误的工具来完成这项工作。

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

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

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

这行代码不是某行可以用 PHPUnit 测试的代码。不要试图在你的 Phpunit 测试中运行这样的代码,你会总是在这里遇到问题。

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

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

该答案还应该告诉您有关从 PHP 发送标头的任何信息,以便您更好地了解您正在测试的系统。

【讨论】:

  • 你是对的。 PHPUnit 可能不是测试这个特定控制器的合适工具。为了我的目的,我会尝试以其他方式对其进行测试。谢谢。
  • 好吧,无论您在那里使用什么基于控制器的系统,如果它要求您直接使用其中的header 函数,那么没有单元测试系统适合测试这些控制器中的任何一个因为这些控制器不是可以在没有所谓的副作用的情况下进行测试的单元。一个单位就是一个单位,没有副作用。所以也许这个控制器系统激励你编写的代码也是一种代码气味。 - 啊好吧,是蛋糕,现在才看到。永远不要浪费任何时间尝试测试 Cake 应用程序。告诉你的客户,测试是站在他这边的。
  • 最后一句话可能听起来很刺耳,但这是有原因的:只有您的客户知道什么对他来说是重要的测试。您仍然可以提供帮助他,但您应该将其设为一个专门的子项目,因为默认情况下,蛋糕应用程序的测试不是软件的固有功能,因此您需要为它扩展软件。这是很多工作,除了编写应用程序之外无事可做。此外,您应该告诉您的客户关于 Cake 的使用条款,尤其是免责声明对他来说很重要(并且许可证要求您向他展示)
【解决方案5】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 2019-10-08
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多