问题
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();
回答1:
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
回答2:
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.
回答3:
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
来源:https://stackoverflow.com/questions/9127252/how-to-test-for-expected-headers