bcmcfc
bcmcfc

Reputation: 26755

How to test for expected headers?

I have a unit test that fails because headers are already sent. However, the header in this scenario is expected.

How do I tell PHPUnit to expect a 500 header?

I've read this question but it didn't help.

The method is wrapped inside an output buffer.

ob_start();
$foo->methodWhichSendsHeader();
ob_clean();

Upvotes: 12

Views: 10725

Answers (3)

Francesco
Francesco

Reputation: 443

Another possible approach is to override the header php function for the namespace you are testing. https://www.codepunker.com/blog/overwrite-built-in-php-functions-using-namespaces

namespace My\Application\Namespace;
use My\Test\Application\Namespace;    

//this overrides the header function for that namespace
//it works only if the function is called without the backslash
function header($string){
    HeaderCollector::$headers[] = $string;
}

namespace My\Test\Application\Namespace

/**
 * Class HeaderCollector
 * Using this in combination with function header override
 * for the namespace My\Application\Namespace
 * we can make assertions on headers sent
 */
class HeaderCollector {

    public static $headers = [];

    //call this in your test class setUp so headers array is clean before each test
    public static function clean() {
        self::$headers = [];
    }
}

Then in your test class

namespace My\Test\Application\Namespace
use PHPUnit\Framework\TestCase;


class MyTest extends TestCase {

    protected function setUp() {
        parent::setUp();
        //clean for each test
        HeaderCollector::clean();
    }

    public function testHeaders() {
        //call the code that send headers
        ...

        self::assertEquals(
            ["Content-Type: text/html; charset=UTF-8", "Another-Header..."],
            HeaderCollector::$headers
        );
    }
}

You can keep your code clean and you don't need xdebug

Upvotes: 2

Peter Bagnall
Peter Bagnall

Reputation: 1851

If you can't use xdebug_get_headers on your system, another approach is to mock the header function.

I'm using the following now, which works great. Lets say you have this code...

<?php
header('Content-type: text/plain; charset=UTF-8');
...

I replace header with a header function which is testable like this...

<?php
Testable::header('Content-type: text/plain; charset=UTF-8');
...

The Testable class is implemented as follows. Note that functions just need to be prepended with Testable::. Otherwise they work just the same as the usual functions.

class Testable {
   private static $headers=array();

   static function header($header) {
      if (defined('UNIT_TESTING')) {
         self::$headers[]=$header;
      } else {
         header($header);
      }
   }

   public static function reset() {
      self::$headers=array();
   }

   public static function headers_list() {
      if (defined('UNIT_TESTING')) {
          return self::$headers;
      } else {
          return headers_list();
      }
   }
}

Now all you need to do is define UNIT_TESTING in your tests, but not in production. Then when you come to test your headers, just call Testable::headers_list().

You should of course add methods for setcookie, headers_sent and any other functions which issue HTTP headers.

Upvotes: 3

Peter Bagnall
Peter Bagnall

Reputation: 1851

If you have xdebug installed you can use xdebug_get_headers() to get the headers. Then you can test them as needed.

$headers=xdebug_get_headers();

gets you an array which looks like...

array(
    0 => "Content-type: text/html",
    1 => ...
)

So you'll need to parse each header line to separate the header name from the value

Upvotes: 21

Related Questions