Перевірте заголовки PHP за допомогою PHPUnit


97

Я намагаюся використовувати 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?

У чому може бути проблема?


14
Просто хотів висвітлити це, якщо є ще хтось зацікавлений у цьому. headers_list () не працює під час запуску PHPunit (який використовує PHP CLI), але xdebug_get_headers () працює замість цього.
titel

Відповіді:


123

Проблема в тому, що 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');
}

7
це спричиняє помилки в деяких операторах define () PHPUnit_Framework_Exception: Примітка: Постійний xyz вже визначений
Minhaz

1
@mebjas Це звучить не пов'язано.
SamHennessy

4
Я отримав це при застосуванні: PHP Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SplFileInfo' is not allowed' in phar:///usr/local/bin/phpunit/phpunit/Util/GlobalState.php:211
t1gor

2
Це, безумовно, найкращий варіант вирішення проблеми. Це спрацювало як шарм!
xarlymg89

2
Мені довелося використовувати xdebug_get_headers (), щоб отримати масив заголовків набору. headers_list () глобальна функція не працювала в моєму випадку.
Шалом Сем

108

Хоча запуск тесту в окремому процесі вирішує проблему, при запуску великого набору тестів відчутні накладні витрати.

Моє виправлення було направити вихід phpunit до stderr, приблизно так:

phpunit --stderr <options>

Це має вирішити проблему, а це також означає, що вам не потрібно створювати функцію обгортки та замінювати всі випадки у вашому коді.


3
Блискуче! Ніяких змін у моєму коді, ніяких окремих процесів, і він працює.
alexfernandez

але чи все одно я побачу помилки, які я зробив, і отримаю результат error_reporting (E_ALL) ??
spankmaster79

1
@ spankmaster79 так, це просто перейде до стандартної помилки вашого терміналу. За замовчуванням більшість терміналів друкують стандартні та стандартні помилки разом, але насправді це окремі потоки.
Джон Кернс,

я ставав зробленим !!! tnx для цього фокусу, він має сенс, про помилки слід повідомляти stderror !!! Tnx
th3n3rd

42
Ви можете додати stderr="true"файл phpunit.xml, щоб зберегти кілька натискань клавіш.
tszming

9

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

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

HTH


4

Як уже зазначалося в коментарі, я вважаю, що це краще рішення визначити processIsolation у файлі конфігурації XML, наприклад

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

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


4
Ймовірно, краще визначити його лише для тесту, який цього вимагає. Якщо встановити його для всіх тестів, тестування буде просто повільним.
Ши

3

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

Це спрацювало для мене як шарм. Але я вважаю, що рішення "joonty" користувача є найкращим з усіх, що працюють на сьогоднішній день.


Ви подали запит на витяг у сховищі? Я думаю, це може бути типовою проблемою.
t1gor

Дякую за підказку, я зателефонував session_start () у моєму phpunit bootstrap.php, і це працює для мене
bumperbox

0

Альтернативним рішенням @runInSeparateProcess є вказати параметр --process-isolation під час запуску PHPUnit:

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

Це аналогічно встановленню опції processIsolation = "true" у phpunit.xml.

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


Це може бути першим кроком у виявленні причини та проведенні деяких тестів, але для того, щоб створити тести, які можна підтримувати, просто вставте анотацію у файл тесту. Чим менше "спеціальних" параметрів потрібно з командного рядка, тим простіше підтримувати конфігурацію системи CI.
Ши

хто коли-небудь знизив # fail. ця відповідь є правильною як інший варіант.
fb

0

Використовуйте параметр --stderr для отримання заголовків з PHPUnit після ваших тестів.

phpunit --stderr
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.