Bagaimana cara menghasilkan CLI selama pelaksanaan tes Unit PHP?

151

Saat menjalankan tes PHPUnit, saya ingin dapat membuang output sehingga saya dapat men-debug satu atau dua hal.

Saya telah mencoba yang berikut (mirip dengan contoh Manual PHPUnit );

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

Dengan hasil sebagai berikut:

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

Perhatikan tidak ada output yang diharapkan.

Saya menggunakan versi HEAD dari git repos pada 19 September 2011.

Output dari php -version:

$ php -version
PHP 5.2.9 (cli) (built: Dec  8 2010 11:36:37) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

Apakah ada yang saya lakukan salah, atau ini berpotensi bug PHPUnit?

Jess Telford
sumber
1
Di mana kode yang memanggil testOutput()metode?
Derrick Tucker
Anda mencoba dengan sangat putus asa (echo, print, print_r, var_dump - ini pada dasarnya semua "output"), biasanya saya tidak punya masalah melakukan output dari tes. Anda dapat memeriksa apakah buffering output diaktifkan: php.net/manual/en/function.ob-get-level.php - Dan cara teraman untuk "menguji" dengan paksa adalah dengan melemparkan pengecualian BTW.
hakre
3
@DerrickTucker PHPUnit melakukan ini dengan memanggil phpunit /path/to/tests/theTest.php(jika kelas di atas ada dalam file theTest.php).
Jess Telford
@Hakre ob_get_level()kembali 1. Namun, ini bertentangan dengan kode berikut: while (ob_get_level() > 0) { ob_end_flush(); }yang salah dengan ob_end_clean(): failed to delete buffer. No buffer to delete.. Ingin tahu dan ingin tahu.
Jess Telford
1
Itu mengatakan bahwa itu kode phpunit yang memicu kesalahan - jelas karena output phpunits menelan aktif (tetapi Anda memecahkannya). Lihat persis, nama fungsi juga berbeda.
hakre

Jawaban:

196

MEMPERBARUI

Baru menyadari cara lain untuk melakukan ini yang bekerja lebih baik daripada --verbose opsi baris perintah:

class TestSomething extends PHPUnit_Framework_TestCase {
    function testSomething() {
        $myDebugVar = array(1, 2, 3);
        fwrite(STDERR, print_r($myDebugVar, TRUE));
    }
}

Ini memungkinkan Anda membuang apa pun ke konsol Anda kapan saja tanpa semua hasil yang tidak diinginkan yang menyertai --verbose opsi CLI.


Seperti yang dicatat oleh jawaban lain, yang terbaik adalah menguji keluaran menggunakan metode bawaan seperti:

$this->expectOutputString('foo');

Namun, kadang-kadang membantu untuk menjadi nakal dan melihat hasil debugging satu kali / sementara dari dalam kasus pengujian Anda. var_dumpMeskipun demikian, tidak perlu melakukan hack / solusi. Ini dapat dengan mudah dicapai dengan mengatur --verboseopsi baris perintah saat menjalankan suite pengujian Anda. Sebagai contoh:

$ phpunit --verbose -c phpunit.xml

Ini akan menampilkan output dari dalam metode pengujian Anda saat berjalan di lingkungan CLI.

Lihat: Menulis Tes untuk PHPUnit - Menguji Output .

rdlowrey
sumber
5
maaf, kangen kita menulis ke stderr. Memang berhasil. Saya hanya terpaksa menggunakan file_put_contents('php://stderr', $myDebugVar, FILE_APPEND);, karena saya punya pesan Use of undefined constant STDERR - assumed 'STDERR'dengan fwrite .
Serge
Masalahnya adalah ini sepertinya tidak bekerja dengan proses isolasi.
donquixote
@donquixote Tidak mengherankan karena tes akan dijalankan dalam proses lain yang keluaran aliran STDERR-nya kemungkinan dibuang ...
rdlowrey
1
Anda juga dapat menggunakan STDOUTbukannyaSTERR
Chris
2
Iya. Ini berfungsi dan tampaknya menghasilkan cara yang sama seperti STDERR. Saya menggunakan PHPUnit 4.5.0baris windows cmd. sebuah echopernyataan tidak memberikan hasil yang sama. echotidak menghasilkan tetapi hanya setelah hasil tes ditampilkan. fwrite(STDERR, 'string')atau fwrite(STDOUT,'string')menghasilkan hasil yang sama: Output sebelum hasil tes ditampilkan.
Chris
33

Pembaruan: Lihat pembaruan rdlowrey di bawah mengenai penggunaan fwrite(STDERR, print_r($myDebugVar, TRUE));sebagai cara yang lebih sederhana


Perilaku ini disengaja (seperti jasonbar telah menunjukkan ). Status manual yang saling bertentangan telah dilaporkan ke PHPUnit.

Sebuah solusi adalah meminta PHPUnit menyatakan bahwa output yang diharapkan kosong (ketika ada output) yang akan memicu output yang tidak diharapkan untuk ditampilkan.

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        $this->expectOutputString(''); // tell PHPUnit to expect '' as output
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

memberi:

PHPUnit @package_version@ by Sebastian Bergmann.

F

Time: 1 second, Memory: 3.50Mb

There was 1 failure:

1) theTest::testOutput
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-''
+'Hello WorldPingPongstring(4) "Foo"
+'

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Pastikan untuk menonaktifkan pernyataan lain yang Anda miliki untuk pengujian karena mungkin gagal sebelum pernyataan keluaran diuji (dan karenanya Anda tidak akan melihat output).

Jess Telford
sumber
33

Coba gunakan --debug

Berguna jika Anda mencoba untuk mendapatkan jalur yang benar ke file data include atau source.

chim
sumber
2
Ini jawaban yang tepat untukku. Semua pernyataan fwrite yang ditulis dalam jawaban sebelumnya tidak bekerja untuk saya.
Kim Stacks
9

Ini bukan bug, tapi sangat disengaja. Taruhan terbaik Anda adalah menulis ke file log dari beberapa jenis dan ekor log untuk melihat hasilnya.

Jika Anda mencoba untuk TEST output, periksa ini .

Juga:

Catatan : Harap dicatat bahwa PHPUnit menelan semua output yang dikeluarkan selama pelaksanaan tes. Dalam mode ketat, tes yang menghasilkan output akan gagal.

jasonbar
sumber
1
Jika itu disengaja, maka pasti manual tidak akan memberikan contohnya ? Juga, tidak mencoba menguji output itu sendiri. Hanya menggunakannya untuk melihat hasil yang menyebabkan tes gagal padahal seharusnya tidak.
Jess Telford
Seperti yang tertulis: Saya biasanya tidak memiliki masalah untuk bergema ketika tes berjalan. Anda mungkin memiliki beberapa konfigurasi yang menarik input.
hakre
1
Jika itu tidak disengaja, maka manual itu tidak akan mengatakan itu .
jasonbar
1
Jadi sepertinya ada konflik dalam dokumentasi. @akre tampaknya berada di bawah kesan yang sama dengan saya (bahwa itu tidak boleh ditelan) - bagian mana dari dokumentasi yang benar?
Jess Telford
Tes penghasil output HANYA gagal ketika --disallow-test-output (atau file conf telah menjadiStrictAboutOutputDuringTests = "true") - dokumentasi sekarang mengatakan "Sebuah tes yang mengeluarkan output, misalnya dengan menjalankan pencetakan baik dalam kode tes atau kode yang diuji, akan ditandai sebagai berisiko ketika pemeriksaan ini diaktifkan. " phpunit.readthedocs.io/en/8.4/risky-tests.html#risky-tests
NULL pointer
7

Saya beruntung dengan VisualPHPUnit , dan itu membantu menampilkan output, antara lain.

class TestHello extends PHPUnit_Framework_TestCase 
{
    public function test_Hello() 
    {
        print "hello world";
    }
}

Hasil TestHello

Bob Stein
sumber
Hmm, mengapa downvote? Bagaimana ini tidak membantu sebagai cara alternatif untuk membuang hasil debug dalam tes PHPUnit?
Bob Stein
1
Saya menduga ini downvoted karena jika ada yang mencoba menjalankan ini Anda akan mendapatkan kesalahan sintaksis. Yang besar.
Jimbo
Saya lupa fungsi. Sekarang sudah diperbaiki, diuji, dipotong dan disisipkan. Terima kasih, @Jimbo
Bob Stein
Sayangnya itu tidak kompatibel dengan PHP 7 saat ini, tampaknya: "VisualPHPUnit tidak kompatibel dengan php 7 saat ini karena cara phpunit digunakan. Php 7 akan didukung dalam rilis utama berikutnya"
le
6

Anda harus benar-benar memikirkan niat Anda: Jika Anda memerlukan informasi sekarang saat debugging untuk memperbaiki tes, Anda akan memerlukannya lagi minggu depan ketika tes pecah.

Ini berarti bahwa Anda akan selalu membutuhkan informasi ketika tes gagal - dan menambahkan avar_dump untuk menemukan penyebabnya terlalu banyak bekerja. Alih-alih memasukkan data ke dalam pernyataan Anda.

Jika kode Anda terlalu rumit untuk itu, pisahkan sampai Anda mencapai tingkat di mana satu pernyataan (dengan pesan khusus) memberi tahu Anda cukup untuk mengetahui di mana itu rusak, mengapa dan bagaimana cara memperbaiki kode.

cweiske
sumber
1
Saya setuju 100% dengan semua yang Anda katakan. Saya menggunakan PHPUnit untuk melakukan tes Integrasi yang akhirnya memanggil salah satu API XML Google. Semua tes Unit lulus (dengan panggilan API diejek), tetapi tes akhir (dengan panggilan API langsung) gagal. Ternyata itu adalah kesalahan Google API tetapi sementara itu, saya ingin membuang respons HTTP mentah.
Jess Telford
2
Bagaimana jika Anda perlu men-debug kode Anda untuk mencapai apa yang telah Anda uraikan di sini?
David Meister
2
Inilah sebabnya saya tidak suka jawaban yang menebak apa yang ingin dilakukan pengguna. Saya di sini karena saya memiliki tes yang menunggu cache dihapus. Dengan 5 detik ttl cache, itu berarti pengujian saya tampaknya hang ~ 16 detik. Saya hanya ingin memancarkan pemberitahuan kepada pengguna bahwa tidak, tidak ada yang salah, kami hanya menunggu cache keluar. Jika orang hanya dapat menjawab pertanyaan, maka orang dengan kasus penggunaan lain juga akan memiliki jawabannya.
user151841
4

Di laravel 5 Anda dapat menggunakan dump (), Dump konten dari respons terakhir.

class ExampleTest extends TestCase{
    public function test1()
    {
        $this->post('/user', ['name' => 'Gema']);
        $this->dump();
    }
}

memberi

Branny Bk
sumber
4

Cukup gunakan flag --verbose saat menjalankan phpunit .

$ phpunit --verbose -c phpunit.xml 

Keuntungan dari metode ini adalah bahwa Anda tidak perlu mengubah kode tes, Anda dapat mencetak string, var_dump adalah apa pun yang Anda inginkan selalu dan itu akan ditampilkan di konsol hanya ketika verbose mode diatur.

Saya harap ini membantu.

Fabricio
sumber
3

Untuk beberapa kasus, seseorang dapat menggunakan sesuatu seperti itu untuk mengeluarkan sesuatu ke konsol

class yourTests extends PHPUnit_Framework_TestCase
{
    /* Add Warnings */
    protected function addWarning($msg, Exception $previous = null)
    {
        $add_warning = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_Warning($msg, 0, $previous);
        $add_warning->addWarning($this, $msg, time());
        $this->setTestResultObject($add_warning);
    }

    /* Add errors */
    protected function addError($msg, Exception $previous = null)
    {
        $add_error = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_error->addError($this, $msg, time());
        $this->setTestResultObject($add_error);
    }

    /* Add failures */
    protected function addFailure($msg, Exception $previous = null)
    {
        $add_failure = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_failure->addFailure($this, $msg, time());
        $this->setTestResultObject($add_failure);
    }

    public function test_messages()
    {
        $this->addWarning("Your warning message!");
        $this->addError("Your error message!");
        $this->addFailure("Your Failure message");
    }

    /* Or just mark test states! */
    public function test_testMarking()
    {
        $this->markTestIncomplete();
        $this->markTestSkipped();
    }
}
mkungla
sumber
3

Meretas, tetapi berfungsi: Lempar pengecualian dengan hasil debug sebagai pesannya.

class theTest extends PHPUnit_Framework_TestCase
{
    public function testOutput() {
        throw new \Exception("hello");
    }   
}

Hasil:

...
There was 1 error:

1) theTest::testOutput
Exception: hello
Matthias Rella
sumber
2

Ini diambil dari PHPUnit Documents tentang Jadwal .

Ini akan memungkinkan Anda untuk membuang informasi kapan saja selama siklus hidup pengujian phpunit.

Cukup ganti __METHOD__dalam kode di bawah ini dengan apa pun yang Anda ingin hasilkan

Contoh 4.2: Contoh menunjukkan semua metode templat yang tersedia

<?php
class TemplateMethodsTest extends PHPUnit_Framework_TestCase
{
    public static function setUpBeforeClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function setUp()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function assertPreConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public function testOne()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(TRUE);
    }

    public function testTwo()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(FALSE);
    }

    protected function assertPostConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function tearDown()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public static function tearDownAfterClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function onNotSuccessfulTest(Exception $e)
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        throw $e;
    }
}
?>
Chris
sumber
1

Saya mengeluarkan Testresult saya berbasis HTML, dalam hal ini sangat membantu untuk menyiram konten:

var_dump($array);
ob_flush();

Ada Metode PHP kedua

flush() 

yang belum saya coba.

Sudo
sumber
1

PHPUnit menyembunyikan output dengan ob_start(). Kami dapat menonaktifkannya sementara.

    public function log($something = null)
    {
        ob_end_clean();
        var_dump($something);
        ob_start();
    }
Slawa
sumber
0

Saya harus mengubah kode sumber agar kode ini berfungsi sehingga Anda perlu menambahkan URL untuk repo bercabang ini ke komposer karena ini akan berfungsi

class TestCase extends \PHPUnit_Framework_TestCase
{
    /**
     *  Save last response
     * @var Response|null A Response instance
     */
    static $lastResponse;
    /**
     *  Modify to save response
     *
     * @param  string $method
     * @param  string $uri
     * @param  array $parameters
     * @param  array $files
     * @param  array $server
     * @param  string $content
     * @param  bool $changeHistory
     * @return \Illuminate\Http\Response
     */
    final public function call(
        $method,
        $uri,
        $parameters = [],
        $files = [],
        $server = [],
        $content = null,
        $changeHistory = true
    ) {

        $response = parent::call($method, $uri, $parameters, $files, $server, $content, $changeHistory);
        static::$lastResponse = $this->client->getResponse();
        return $response;
    }


    /**
     * Modify message to add response text
     *
     * @param mixed $value
     * @param PHPUnit_Framework_Constraint $constraint
     * @param string $message
     * @since  Method available since Release 3.0.0
     */
    final public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '')
    {
        $message .= PHP_EOL . static::$lastResponse . PHP_EOL;
        parent::assertThat($value, $constraint, $message);
    }
}
Gadelkareem
sumber
0

Berikut adalah beberapa metode yang berguna untuk mencetak pesan debug di PHPUnit 4.x:

  • syslog(LOG_DEBUG, "Debug: Message 1!");

    Contoh yang lebih praktis:

    syslog(LOG_DEBUG, sprintf("%s: Value: %s", __METHOD__, var_export($_GET, TRUE)));

    Memanggil syslog()akan menghasilkan pesan log sistem (lihat man syslog.conf:).

    Catatan: tingkat Kemungkinan: LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING,LOG_ERR , dll

    Di macOS, untuk melakukan streaming pesan syslog secara realtime, jalankan:

    log stream --level debug --predicate 'processImagePath contains "php"'
  • fwrite(STDERR, "LOG: Message 2!\n");

    Catatan: STDERRKonstanta tidak tersedia jika membaca skrip PHP dari stdin . Ini solusinya .

    Catatan: Alih-alih STDERR, Anda juga dapat menentukan nama file.

  • file_put_contents('php://stderr', "LOG: Message 3!\n", FILE_APPEND);

    Catatan: Gunakan metode ini, jika Anda tidak memiliki definisi STDERRkonstan .

  • register_shutdown_function('file_put_contents', 'php://stderr', "LOG: Message 4!\n", FILE_APPEND);

    Catatan: Gunakan metode ini, jika Anda ingin mencetak sesuatu di bagian paling akhir tanpa mempengaruhi tes.

Untuk membuang variabel, gunakan var_export(), misalnya"Value: " . var_export($some_var, TRUE) . "\n" .

Untuk mencetak pesan di atas hanya selama mode verbose atau debug, lihat: Apakah ada cara untuk mengetahui apakah --debug atau --verbose diteruskan ke PHPUnit dalam pengujian?


Meskipun jika menguji output adalah bagian dari pengujian itu sendiri, periksa: halaman Testing Output docs.

kenorb
sumber
-1

Jika Anda menggunakan Laravel, maka Anda dapat menggunakan fungsi logging seperti info () untuk masuk ke file log Laravel di bawah penyimpanan / log. Jadi itu tidak akan muncul di terminal Anda tetapi di file log.

Leo
sumber