2

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.

mmrn
  • 249
  • 2
  • 8
  • 18

5 Answers5

3

Check if you are giving any output before your header line,usually its an echo,maybe you are echo ing some html before your header line

christmas
  • 154
  • 1
  • 7
  • I'm not sending any output before header. If someone is sending, it must be CakePHP testing unit. I'm looking for how to stop this. – mmrn Sep 27 '13 at 04:46
1

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.

Sven
  • 69,403
  • 10
  • 107
  • 109
  • I see. Somehow CakeResponse did not work well in my situation, so I had to use header() function for this controller. I think some controllers like this may not be suitable for unit-testing. I'll look for a workaround or some other way. – mmrn Sep 29 '13 at 06:17
1

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.

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • You are right. PHPUnit may not be a suitable tool to test this specific controller. I'll try to test it in some other way for my purpose. Thanks. – mmrn Sep 29 '13 at 06:21
  • Well whatever controller-based system you're using there, if it requires you to use the `header` function in there directly, no unit-test system is a suitable tool to test any of these controllers because these controllers are no units that can be tested without so called side-effects. A unit is a unit, there are no side-effects. So perhaps the code that this controller system motivates you to write is a also a code-smell. - Ah okay, it's Cake, just seeing now. Never wasted any time trying to test a Cake app. Tell your client that testing is on his side. – hakre Sep 29 '13 at 06:23
  • This last sentence might sound harsh, but there is a reason for it: Only your customer knows what is important for him to test for. You can still offer to help him with that, but you should make it a dedicated sub-project because by default testing of a cake app is not an inherent feature of the software so you need to extend the software for it. It's much work, nothing to do just next to writing the application. Also you should tell your customer about the usage terms of Cake, especially the disclaimer is important for him to know (and the license requires acutally that you show it to him) – hakre Sep 29 '13 at 06:30
0

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.

Community
  • 1
  • 1
Konsole
  • 3,447
  • 3
  • 29
  • 39
  • 1
    That answer is talking about general cases, but I'm asking about testing situation. My functions are not outputting anything before header function. But in CakePHP testing, the tests run in sequence, so the situation is different and I get the errors. – mmrn Sep 27 '13 at 04:14
0

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.

Boynux
  • 5,958
  • 2
  • 21
  • 29