Domanda

I have a function that creates CSV data and lets the user download it in the browser, basically like this:

function f() {
  if ($fp = fopen('php://output', 'w')) {
    header("Content-Type: text/csv");
    header("Content-Disposition: attachment; filename=\"foo.csv\"");
    fputcsv($fp, $someArrayGoesHere);
    flush();
    fclose($fp);

    // debugging, explained below
    error_log(print_r(xdebug_get_headers(), true));
  }
}

The code works, presenting the user with a download dialog.

Now, I'm trying to write a PHPunit test to confirm that the two HTTP headers get set. Realizing that headers_list() doesn't work in CLI context (php_sapi_name() == 'cli'), I'm using xdebug_get_headers() to retrieve the headers for testing.

Now comes the trouble. The debugging line in my code above, when run on the web, always prints the headers I expect:

Array
(
    [0] => X-Content-Type-Options: nosniff
    [1] => Content-Type: text/csv
    [2] => Content-Disposition: attachment; filename="foo.csv"
)

But when I run this code in phpunit, the PHPUnit_Util_Printer::write function appears to be producing output before my code sets the headers, and prevents them from being set, producing this debug output:

Cannot modify header information - headers already sent by (output started
at /usr/share/pear/PHPUnit/Util/Printer.php:172)
Array
(
    [0] => Content-type: text/html
)

This earlier write is not being produced by me, so is there a way around it? How do I test for my CSV-related headers using phpunit?

I've already read the advice given in these questions, but it hasn't helped:

I also tried using @runInSeparateProcess with the unit test, but the test crashes horribly: ".Unexpected non-MediaWiki exception encountered, of type "Exception", exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in /usr/share/pear/PHPUnit/Util/GlobalState.php:354". (This is a MediaWiki unit test for a custom extension.)

È stato utile?

Soluzione

The answer to your literal question "Why does PHPUnit interfere with setting HTTP headers in this code?" is given fairly clearly in the answer to Test PHP headers with PHPunit. PHP's header() will fail with the Cannot modify header information warning if anything has been written to stdout. When running your code via PHPUnit, content has been sent to stdout long before your code under test has been reached.

You noted a separate issue when using the @runInSeparateProcess annotation to fork a clean PHP process for your test:

Unexpected non-MediaWiki exception encountered, of type "Exception", exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in /usr/share/pear/PHPUnit/Util/GlobalState.php:354

By default PHPUnit attempts to backup all of the $GLOBALS data before each test and restore it afterwards. MediaWikiTestCase turns this behavior off but it looks like your extension's tests are not. It seems likely that the configuration for your extension includes a closure and is causing the serialization failure. Adding a @backupGlobals disabled annotation to your PHPUnit_Framework_TestCase class should get you past this problem.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top