Проверка заголовков PHP с помощью PHPUnit

Я пытаюсь использовать PHPunit для тестирования класса, который выводит некоторые пользовательские заголовки.

Проблема в том, что на моей машине это:

<?php class HeadersTest extends PHPUnit_Framework_TestCase { public function testHeaders() { ob_start(); header('Location: foo'); $headers_list = headers_list(); header_remove(); ob_clean(); $this->assertContains('Location: foo', $headers_list); } } 

или даже это:

 <?php class HeadersTest extends PHPUnit_Framework_TestCase { public function testHeaders() { ob_start(); header('Location: foo'); header_remove(); ob_clean(); } } 

вернуть эту ошибку:

 name@host [~/test]# phpunit --verbose HeadersTest.php PHPUnit 3.6.10 by Sebastian Bergmann. E Time: 0 seconds, Memory: 2.25Mb There was 1 error: 1) HeadersTest::testHeaders Cannot modify header information - headers already sent by (output started at /usr/local/lib/php/PHPUnit/Util/Printer.php:173) /test/HeadersTest.php:9 FAILURES! Tests: 1, Assertions: 0, Errors: 1. 

Это похоже на то, что есть что-то еще, выводящее на терминал до запуска теста, даже если в него нет другого файла, и перед началом тега PHP нет другого символа. Может ли это быть внутри PHPunit, что вызывает это?

В чем проблема?

Проблема в том, что PHPUnit будет печатать заголовок на экране, и в этот момент вы не сможете добавить больше заголовков.

Работа вокруг заключается в проведении теста в изолированном процессе. Вот пример

 <?php class FooTest extends PHPUnit_Framework_TestCase { /** * @runInSeparateProcess */ public function testBar() { header('Location : http://foo.com'); } } 

Это приведет к:

 $ phpunit FooTest.php PHPUnit 3.6.10 by Sebastian Bergmann. . Time: 1 second, Memory: 9.00Mb OK (1 test, 0 assertions) 

Ключ – аннотация @runInSeparateProcess.

Если вы используете PHPUnit ~ 4.1 или что-то еще и получите ошибку:

 PHP Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in -:378 Stack trace: #0 {main} thrown in - on line 378 Fatal error: Uncaught Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378 Error: Class 'PHPUnit_Util_Configuration' not found in - on line 378 Call Stack: 0.0013 582512 1. {main}() -:0 

Попробуйте добавить это в свой файл начальной загрузки, чтобы исправить это:

 <?php if (!defined('PHPUNIT_COMPOSER_INSTALL')) { define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php'); } 

Несмотря на то, что запуск теста в отдельном процессе устраняет проблему, при выполнении большого набора тестов есть заметные накладные расходы.

Мое исправление заключалось в том, чтобы направить вывод phpunit на stderr, например:

 phpunit --stderr <options> 

Это должно устранить проблему, а это также означает, что вам не нужно создавать функцию-оболочку и заменять все вхождения в вашем коде.

В стороне: для меня headers_list() продолжал возвращать 0 элементов. Я заметил комментарий @titel по этому вопросу и подумал, что это заслуживает особого упоминания здесь:

Просто хотел, чтобы охватить это, если есть и другие люди, заинтересованные в этом. headers_list() не работает во время работы PHPunit (который использует PHP CLI), но вместо этого работает xdebug_get_headers() .

НТН

У меня было более радикальное решение, чтобы использовать $_SESSION внутри моих тестируемых / включенных файлов. Я редактировал один из файлов PHPUnit на ../PHPUnit/Utils/Printer.php, чтобы иметь "session_start();" перед командой «print $ buffer» .

Это работало для меня как шарм. Но я думаю, что пользовательское решение «joonty» является лучшим из всех до сих пор.

Как уже упоминалось в комментарии, я думаю, что это лучшее решение для определения processIsolation в файле конфигурации XML, например

  <?xml version="1.0" encoding="UTF-8"?> <phpunit processIsolation = "true" // ... > </phpunit> 

Таким образом, вам не нужно передавать параметр –stderr, что может раздражать ваших сотрудников.

Альтернативным решением для @runInSeparateProcess является указание опции -process-изоляции при запуске PHPUnit:

 name@host [~/test]# phpunit --process-isolation HeadersTest.php 

Это аналогично заданию параметра processIsolation = "true" в phpunit.xml.

Это решение имеет схожие преимущества / недостатки с указанием опции -stderr, которая, однако, не работает в моем случае. В принципе, никаких изменений кода не требуется, даже несмотря на то, что может произойти поражение производительности из-за запуска каждого теста в отдельном PHP-процессе.