简体   繁体   中英

CakePHP testing: Cannot modify header information - headers already sent by

Note: this is not a duplicate question. I've seen some similar questions but I'm asking about unit testing.

I'm trying to write test cases using CakePHP 2.3.6 and having problems with the test cases that use header() function. The test runs with no problem from a browser, but from command line, I get the following error.

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

The error is occurring at the following line in my code, for example.

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

For PHPUnit, @runInSeparateProcess can be used for avoiding this, but in CakePHP, it causes the following errors instead.

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

and so on.

I'm stuck. Does anyone know how to handle this? Thanks a lot in advance.

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

All the other answers for questions regarding "headers already sent" are right, but in your case it's some kind of specialty. You cannot escape that situation, because PHPUnit does send output before running into your code that tries to send a header.

But the key point is: You are not supposed to use the header() function. You are supposed to use the CakeResponse object for that. My quick googling found this (which apparently is for 2.0, so you should probably find an updated documentation version): http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse

If using this object, the whole testing process can avoid calling header() during test execution, because you could inject a mock object like this: http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse-and-testing

In the end, the following basic rules apply to your code if you want to run tests smoothly:

  • do not call any PHP function that depends on a situation (like headers() depend on not having an echo first) or alters that situation
  • do not call PHP functions that you need to have tested (like "there must be a call to error_log happening")

All these function calls should be wrapped into an object that can be mocked.

You must have misunderstood what Unit-Tests actually are. So take care here that you're not using the wrong tool for the job.

For example, in your question your wrote:

The error is occurring at the following line in my code, for example.

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

This line of code is not some line of code that can be tested using PHPUnit. Don't try to run such code in your Phpunit tests, you will always run into problems here.

So you write correctly that you're stuck, I can perfectly understand that. However that depends on point of view as well. Some problems have a pretty obvious solution: Don't do so. Instead use the right tool to test that, for example with functional tests that access your application via the HTTP protocol so that they can test for HTTP response headers. PHPUnit can not - well I should not say never here: At least not by the way you use it (and I assume you want to use it).

If that is not an option, the canonical question about the header error outlines many ways how to deal with that error, the there suggested output control functions might be useful with your tests:

That answer should also tell you anything you need to know about sending headers from PHP so you understand the system you have under test better.

NO OUTPUT SHOULD BE SENT BEFORE SENDING HEADERS!

Functions that send/modify HTTP headers must be invoked before any output is made. Otherwise the call fails. Look for any errors output to the screen or any print or echo statements.

See accepted answer here .

The problem is that, your approach is not right! PHPUnit is supposed to do UNIT tests but what you are trying to do is more behavioural tests which can be done using Behat/Mink like tests.

If you are going to use Unit tests then you have to decouple units of your system and do the testing Unit by Unit, in case of redirection you can use mockups to catch redirection functionality and do a proper checking for that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM