Uji header PHP dengan PHPUnit

99

Saya mencoba menggunakan PHPunit untuk menguji kelas yang menghasilkan beberapa header khusus.

Masalahnya adalah di komputer saya ini:

<?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);
    }
}

atau bahkan ini:

<?php

class HeadersTest extends PHPUnit_Framework_TestCase {

    public function testHeaders()
    {
        ob_start();

        header('Location: foo');
        header_remove();

        ob_clean();
    }
}

kembalikan kesalahan ini:

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.

Ini terlihat seolah-olah ada sesuatu yang lain yang dikeluarkan ke terminal sebelum pengujian dijalankan meskipun tidak ada file lain yang disertakan dan tidak ada karakter lain sebelum permulaan tag PHP. Mungkinkah ada sesuatu di dalam PHPunit yang menyebabkan ini?

Apa masalahnya?

titel
sumber
14
Hanya ingin menutupi ini jika ada beberapa orang lain yang tertarik dengan ini juga. headers_list () tidak berfungsi saat menjalankan PHPunit (yang menggunakan PHP CLI) tetapi xdebug_get_headers () berfungsi sebagai gantinya.
titel

Jawaban:

124

Masalahnya adalah PHPUnit akan mencetak header ke layar dan pada saat itu Anda tidak dapat menambahkan lebih banyak header.

Solusinya adalah menjalankan pengujian dalam proses yang terisolasi. Berikut ini contohnya

<?php

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

Ini akan menghasilkan:

$ phpunit FooTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 1 second, Memory: 9.00Mb

OK (1 test, 0 assertions)

Kuncinya adalah anotasi @runInSeparateProcess.

Jika Anda menggunakan PHPUnit ~ 4.1 atau sesuatu dan mendapatkan kesalahan:

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

Coba tambahkan ini ke file bootstrap Anda untuk memperbaikinya:

<?php
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
    define('PHPUNIT_COMPOSER_INSTALL', __DIR__ . '/path/to/composer/vendors/dir/autoload.php');
}
SamHennessy
sumber
7
ini menyebabkan kesalahan di ada beberapa pernyataan define () PHPUnit_Framework_Exception: Perhatikan: Konstan xyz sudah ditentukan
Minhaz
1
@mebjas Kedengarannya tidak ada hubungannya.
SamHennessy
4
Saya mendapatkan ini ketika diterapkan: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
Ini jelas merupakan pilihan terbaik untuk menyelesaikan masalah. Ini bekerja seperti pesona!
xarlymg89
2
Saya harus menggunakan xdebug_get_headers (), untuk mendapatkan array set header. headers_list () fungsi global tidak berfungsi dalam kasus saya.
Shalom Sam
108

Meskipun menjalankan pengujian dalam proses terpisah dapat memperbaiki masalah, ada overhead yang terlihat saat menjalankan serangkaian pengujian yang besar.

Perbaikan saya adalah mengarahkan output phpunit ke stderr, seperti:

phpunit --stderr <options>

Itu seharusnya memperbaiki masalah, dan itu juga berarti bahwa Anda tidak perlu membuat fungsi pembungkus dan mengganti semua kejadian dalam kode Anda.

Jon Cairns
sumber
3
Cemerlang! Tidak ada perubahan pada kode saya, tidak ada proses terpisah, dan berfungsi.
alexfernandez
tetapi apakah saya masih melihat kesalahan yang saya buat dan mendapatkan output dari error_reporting (E_ALL) ??
spankmaster79
1
@ spankmaster79 ya, ini hanya akan menuju ke kesalahan standar terminal Anda. Secara default, kebanyakan terminal akan mencetak standard out dan standard error bersamaan, tapi sebenarnya mereka adalah stream yang terpisah.
Jon Cairns
saya menjadi dibuat !!! tnx untuk trik ini, masuk akal, kesalahan harus dilaporkan ke stderror !!! Tnx
th3n3rd
42
Anda dapat menambahkan stderr="true"phpunit.xml Anda untuk menyimpan beberapa penekanan tombol.
tszming
10

Sebagai tambahan: Bagi saya headers_list()terus mengembalikan 0 elemen. Saya melihat komentar @titel tentang pertanyaan itu dan menurut saya itu layak untuk disebutkan secara khusus di sini:

Hanya ingin menutupi ini jika ada beberapa orang lain yang tertarik dengan ini juga. headers_list()tidak berfungsi saat menjalankan PHPunit (yang menggunakan PHP CLI) tetapi xdebug_get_headers()berfungsi sebagai gantinya.

HTH

Melle
sumber
4

Seperti yang telah disebutkan dalam komentar, saya pikir ini adalah solusi yang lebih baik untuk mendefinisikan processIsolation dalam file konfigurasi XML seperti

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

Seperti ini, Anda tidak harus melewatkan opsi --stderr, yang mungkin mengganggu rekan kerja Anda.

PepeNietnagel
sumber
4
Mungkin lebih baik untuk mendefinisikannya hanya untuk pengujian yang membutuhkannya. Menyetelnya untuk semua pengujian hanya akan membuat pengujian berjalan lambat.
Shi
3

Saya memiliki solusi yang lebih radikal, untuk digunakan $_SESSIONdi dalam file yang saya uji / disertakan . Saya mengedit salah satu file PHPUnit di ../PHPUnit/Utils/Printer.php agar memiliki "session_start();"sebelum perintah "print $ buffer" .

Ini bekerja untuk saya seperti pesona. Tapi menurut saya solusi pengguna "joonty" adalah yang terbaik hingga saat ini.

Sergio Abreu
sumber
Apakah Anda mengirimkan permintaan tarik di repositori? Saya kira ini mungkin masalah umum.
t1gor
Terima kasih atas petunjuknya, saya menelepon session_start () di bootstrap.php phpunit saya dan berfungsi untuk saya
bumperbox
0

Solusi alternatif untuk @runInSeparateProcess adalah menentukan opsi --process-isolation saat menjalankan PHPUnit:

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

Ini serupa dengan menyetel opsi processIsolation = "true" di phpunit.xml.

Solusi ini memiliki kelebihan / kekurangan yang sama dengan menentukan opsi --stderr, yang bagaimanapun tidak berfungsi dalam kasus saya. Pada dasarnya tidak ada perubahan kode yang diperlukan, meskipun mungkin ada kinerja yang terhambat karena menjalankan setiap pengujian dalam proses PHP yang terpisah.

AlexB
sumber
Ini mungkin langkah pertama dalam melacak penyebabnya dan melakukan beberapa pengujian, tetapi untuk membuat pengujian yang dapat dipelihara, cukup sematkan anotasi secara langsung ke dalam file pengujian. Semakin sedikit opsi 'khusus' yang diperlukan dari baris perintah, semakin mudah pemeliharaan konfigurasi sistem CI.
Shi
yang pernah menurunkan #fail. jawaban ini benar sebagai pilihan lain.
fb
0

Gunakan parameter --stderr untuk mendapatkan header dari PHPUnit setelah pengujian Anda.

phpunit --stderr
NSukonny
sumber