Я пытаюсь использовать 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-процессе.