Тестируйте заголовки PHP с помощью PHPUnit - PullRequest
82 голосов
/ 17 марта 2012

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

В чем может быть проблема?

Ответы [ 6 ]

111 голосов
/ 17 марта 2012

Проблема в том, что 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');
}
99 голосов
/ 30 мая 2012

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

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

phpunit --stderr <options>

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

8 голосов
/ 06 октября 2016

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

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

НТН

3 голосов
/ 09 ноября 2013

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

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

0 голосов
/ 12 июня 2017

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

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

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

0 голосов
/ 23 января 2016

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

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

Это аналогично установке параметра processIsolation = "true" в phpunit.xml.

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

...