PHP Birim testlerinin yürütülmesi sırasında CLI'de nasıl çıktı alınır?


158

Bir PHPUnit testi çalıştırırken, bir veya iki şeyde hata ayıklayabilmek için çıktıyı dökmek istiyorum.

Aşağıdakileri denedim ( PHPUnit Manual örneğine benzer );

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

Aşağıdaki sonuçla:

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

Beklenen çıktıların hiçbirinin olmadığına dikkat edin.

Git depolarının HEAD sürümlerini 19 Eylül 2011 itibarıyla kullanıyorum.

Çıktı 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

Yanlış yaptığım bir şey var mı, yoksa bu bir PHPUnit hatası mı?


1
testOutput()Yöntemi çağıran kod nerede ?
Derrick Tucker

Gerçekten umutsuzca deniyorsunuz (echo, print, print_r, var_dump - temelde hepsi "çıktı"), normalde testlerden çıktı alırken sorun yaşamıyorum. Çıktı tamponlamanın etkin olup olmadığını kontrol edebilirsiniz: php.net/manual/en/function.ob-get-level.php - Ve zorla "test etmenin" en güvenli yolu bir BTW istisnası atmaktır.
hakre

3
@DerrickTucker PHPUnit bunu çağırarak yapar phpunit /path/to/tests/theTest.php(yukarıdaki sınıf dosya içindeyse theTest.php).
Jess Telford

@hakre ob_get_level()döndürür 1. Bununla birlikte, bu aşağıdaki kodla çelişir: while (ob_get_level() > 0) { ob_end_flush(); }hangi ile hata ob_end_clean(): failed to delete buffer. No buffer to delete.. Daha meraklı ve daha meraklı.
Jess Telford

1
Hatayı tetikleyen şeyin phpunit'in kodu olduğunu söylüyor - açıkçası phpunits çıktı yutma aktif olduğu için (ama siz onu kırdınız). Kesin olarak bakın, işlev adı da farklıdır.
hakre

Yanıtlar:


203

GÜNCELLEME

Bunu yapmanın --verbosekomut satırı seçeneğinden çok daha iyi çalışan başka bir yolunu keşfettim:

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

Bu, --verboseCLI seçeneğiyle birlikte gelen tüm istenmeyen çıktılar olmadan herhangi bir zamanda konsolunuza her şeyi dökmenizi sağlar.


Diğer yanıtların da belirttiği gibi, en iyisi, aşağıdaki gibi yerleşik yöntemleri kullanarak çıktıyı test etmektir:

$this->expectOutputString('foo');

Bununla birlikte, bazen yaramaz olmak ve test senaryolarınızdan bir defalık / geçici hata ayıklama çıktısını görmek yararlı olabilir. Yine de, var_dumpkesmeye / geçici çözüme gerek yoktur . Bu, --verbosetest paketinizi çalıştırırken komut satırı seçeneğini ayarlayarak kolayca gerçekleştirilebilir . Örneğin:

$ phpunit --verbose -c phpunit.xml

Bu, CLI ortamında çalışırken test yöntemlerinizin içinden çıktıyı gösterecektir.

Bkz: PHPUnit için Testler Yazma - Çıktıyı Test Etme .


5
üzgünüm, cevapsız stderr'e yazıyoruz. Gerçekten çalışır. Onun file_put_contents('php://stderr', $myDebugVar, FILE_APPEND);yerine kullanmaya zorlandım çünkü fwriteUse of undefined constant STDERR - assumed 'STDERR' ile mesajım vardı .
Serge

Sorun şu ki, bu süreç izolasyonuyla işe yaramıyor.
donquixote

@donquixote Test, STDERR akış çıktısı büyük olasılıkla atılan başka bir işlemde yürütüldüğünden şaşırtıcı değil ...
rdlowrey

1
Bunun STDOUTyerine kullanabilirsinizSTERR
Chris

2
Evet. Aynı şekilde çalışıyor ve çıktı veriyor gibi görünüyor STDERR. Ben kullanıyorum PHPUnit 4.5.0pencerelerde cmd çizgi. bir echoifade aynı sonuçları vermez. echoçıktı verir, ancak yalnızca test sonucu görüntülendikten sonra. fwrite(STDERR, 'string')veya fwrite(STDOUT,'string')aynı sonuçları üretir: Test sonucu görüntülenmeden önce bir çıktı.
Chris

35

Güncelleme: Aşağıdaki rdlowrey güncellemesine bakın .fwrite(STDERR, print_r($myDebugVar, TRUE)); daha basit bir iş, etrafımızda olarak


Bu davranış kasıtlıdır ( jasonbar'ın da belirttiği gibi ). Kılavuzun çelişkili durumu rapor edildi PHPUnit'e .

Çözüm, PHPUnit'in beklenen çıktının boş olduğunu iddia etmesini sağlamaktır (infact çıktı olduğunda) ve bu, gösterilecek beklenmedik çıktıyı tetikler.

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

verir:

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.

Test için sahip olduğunuz diğer tüm iddiaları devre dışı bıraktığınızdan emin olun, çünkü bunlar çıktı iddiası test edilmeden önce başarısız olabilir (ve dolayısıyla çıktıyı göremezsiniz).


33

Kullanmayı dene --debug

Dahil etme veya kaynak veri dosyasına giden doğru yolu bulmaya çalışıyorsanız kullanışlıdır.


2
Bu benim için doğru cevap. Önceki cevaplarda yazılan tüm fwrite ifadeleri benim için işe yaramadı.
Kim Stacks

9

Bu bir hata değil, çok kasıtlı. En iyisi, bir tür günlük dosyasına yazmak ve çıktıyı izlemek için günlüğü kuyruklamaktır.

Eğer TEST çıkışına çalışıyorsanız, kontrol bu dışarı.

Ayrıca:

Not : PHPUnit'in bir testin yürütülmesi sırasında gönderilen tüm çıktıları yutacağını lütfen unutmayın. Katı modda, çıktı yayan bir test başarısız olur.


1
Kasıtlı olsaydı, el kitabı buna bir örnek vermez miydi ? Ayrıca çıktının kendisini test etmeye çalışmamak. Sadece bazı sonuçlara göz atmak için kullanmak, testlerin yapılmaması gerektiğinde başarısız olmasına neden olur.
Jess Telford

Yazıldığı gibi: Normalde testler çalışırken yankılanacak bir sorunum yok. Giriş yakalayan bazı yapılandırmalarınız olabilir.
hakre

1
Kasıtlı olmasaydı, el kitabı öyle olduğunu söylemezdi .
jasonbar

1
Yani dokümantasyonda bir çelişki var gibi görünüyor. @hakre benimle aynı izlenime sahip görünüyor (yutulmaması gerektiği) - belgelerin hangi kısmı doğru?
Jess Telford

Çıktı üretme testleri YALNIZCA --disallow-test-output (veya conf dosyası beStrictAboutOutputDuringTests = "true" olduğunda) başarısız olur - dokümantasyon artık "Örneğin test kodunda veya test edilen kodda print çağırarak çıktı yayan bir test" diyor. bu kontrol etkinleştirildiğinde riskli olarak işaretlenecek. " phpunit.readthedocs.io/en/8.4/risky-tests.html#risky-tests
NULL pointer

7

VisualPHPUnit ile biraz şansım var ve diğer şeylerin yanı sıra çıktıyı faydalı bir şekilde gösteriyor.

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

TestHello sonuçları


Hmm, neden olumsuz oy? Bu, bir PHPUnit testinde hata ayıklama çıktısını dökmenin alternatif bir yolu olarak nasıl yardımcı olmaz?
Bob Stein

1
Ben değilim tahmin herkes çalışır, bu çalışan eğer bir sözdizimi hatası alırsınız çünkü bu downvoted edilir. Devasa bir tane.
Jimbo

D'oh, işlevi unuttum. Şimdi sabitlendi, test edildi, kesildi ve yapıştırıldı. Teşekkürler, @Jimbo
Bob Stein

Maalesef şu anda PHP 7 ile uyumlu değil, görünüşe göre: "VisualPHPUnit şu anda phpunit'in kullanılma şekli nedeniyle php 7 ile uyumlu değil. Php 7 bir sonraki büyük sürümde desteklenecek"
leo

6

Niyetinizi gerçekten düşünmelisiniz: Eğer testi düzeltmek için hata ayıklarken şimdi bilgiye ihtiyacınız varsa, gelecek hafta testler bittiğinde tekrar ihtiyacınız olacak.

Bu , test başarısız olduğunda her zaman bilgiye ihtiyaç duyacağınız anlamına gelir var_dumpve nedeni bulmak için a eklemek çok fazla çaba gerektirir. Bunun yerine, verileri iddialarınıza ekleyin.

Kodunuz bunun için çok karmaşıksa, bir iddianın (özel bir mesajla) nerede kırıldığını, neden ve nasıl düzeltileceğini bilmeniz için size yeterince bilgi verdiği bir düzeye ulaşıncaya kadar bölün.


1
Söylediğin her şeye% 100 katılıyorum. Nihayetinde Google'ın XML API'lerinden birini çağıran Entegrasyon testleri yapmak için PHPUnit kullanıyorum. Tüm Birim testleri geçti (API çağrıları alay edildi), ancak son test (canlı API çağrılarıyla) başarısız oldu. Bunun Google API'nin hatası olduğu ortaya çıktı, ancak bu arada ham HTTP yanıtını dökmek istedim.
Jess Telford

2
Ya burada özetlediklerinizi elde etme yolunda kodunuzda hata ayıklamanız gerekirse?
David Meister

2
Bu yüzden kullanıcıların ne yapmak istediğini tahmin eden cevapları sevmiyorum. Buradayım çünkü önbellek temizleme için beklemeyi test ettim. 5 saniyelik önbellek ttls ile bu, testimin yaklaşık 16 saniye askıda kaldığı anlamına geliyor . Kullanıcıya hayır, hiçbir şeyin yanlış olmadığını, sadece önbelleklerin zaman aşımına uğramasını bekliyoruz diye bir uyarı göndermek istiyorum. İnsanlar soruyu sadece cevaplayabilirse, diğer kullanım durumlarına sahip kişilerin de cevabı olacaktır.
user151841

4

Laravel 5'te dump () kullanabilirsiniz, içeriği son yanıttan boşaltın.

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

verir


4

Sadece phpunit'i çalıştırırken --verbose bayrağını kullanın .

$ phpunit --verbose -c phpunit.xml 

Bu yöntemin avantajı, test kodunu değiştirmenize gerek olmaması, dizeleri yazdırabilmeniz, var_dump her zaman istediğiniz her şeyi ve konsolda yalnızca ayrıntılı mod ayarlandığında gösterilmesidir.

Umarım bu yardımcı olur.


3

Bazı durumlarda, konsola bir şey çıkarmak için böyle bir şey kullanılabilir.

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

3

Bu, Fikstürlerle ilgili PHPUnit Belgelerinden alınmıştır .

Bu, phpunit testi yaşam döngüsü boyunca herhangi bir noktada bilgileri dökmenize izin vermelidir.

__METHOD__Aşağıdaki kodu çıktı almak istediğiniz şeyle değiştirin

Örnek 4.2: Mevcut tüm şablon yöntemlerini gösteren örnek

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

3

Hackish, ancak çalışıyor: Mesaj olarak hata ayıklama çıktısıyla bir istisna atın.

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

Getiri:

...
There was 1 error:

1) theTest::testOutput
Exception: hello

1

Testresults çıktımı HTML tabanlı olarak verdim, bu durumda içeriği temizlemek yardımcı oldu:

var_dump($array);
ob_flush();

İkinci bir PHP Yöntemi var

flush() 

ki denemedim.


1

PHPUnit çıktıyı ob_start(). Geçici olarak devre dışı bırakabiliriz.

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

0

Bu kodun çalışması için kaynak kodunu değiştirmem gerekiyordu, bu yüzden bu çatallı depoların URL'sini oluşturucuya eklemeniz gerekiyor, bunun çalışması için

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

0

PHPUnit 4.x'te hata ayıklama mesajlarını yazdırmak için yararlı birkaç yöntem şunlardır:

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

    Daha pratik bir örnek:

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

    Arama syslog(), bir sistem günlüğü mesajı oluşturacaktır (bakınız:) man syslog.conf.

    Not: Olası seviyelerini: LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING,LOG_ERR , vb

    MacOS'ta, sistem günlüğü mesajlarını gerçek zamanlı olarak yayınlamak için şunu çalıştırın:

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

    Not: STDERRPHP betiğini stdin'den okurken sabit kullanılamaz . İşte geçici çözüm .

    Not: Bunun yerine STDERRbir dosya adı da belirtebilirsiniz.

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

    Not: STDERRSabit tanımlı değilseniz bu yöntemi kullanın .

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

    Not: Testleri etkilemeden en sonunda bir şeyler yazdırmak istiyorsanız bu yöntemi kullanın.

Değişkeni dökmek için var_export(), örneğin kullanın "Value: " . var_export($some_var, TRUE) . "\n".

Yukarıdaki iletileri yalnızca ayrıntılı veya hata ayıklama modunda yazdırmak için, bkz: Bir testte PHPUnit'e --debug veya --verbose'un geçip geçmediğini anlamanın bir yolu var mı?


Çıktının test edilmesi kendi kendini test etmenin bir parçası olsa da, şu göz atın : Çıktıyı Test Etme belgeleri sayfası.


0

Kısaca, phpunit STDOUT'u bastırır. --verboseVeya eklemediğiniz sürece, varsayılan olarak STDERR'ye yazar --debug. Bunlardan birini yapabilirsiniz:

  • bunun yerine hata ayıklama çıktınızı STDERR'ye yazdırın
  • var_dumpher zamanki gibi hata ayıklamanız ancak --verbosephpunit komut satırına ekleyin
  • var_dumpher zamanki gibi hata ayıklamanız ancak ob_flush();altına bir satır ekleyin
  • tam olarak burada test etmeye çalıştığınız şeyi test etmek için phpunit'te doğru komutları kullanın

Açıkçası, yapılacak en son şey yapılacak İyi Şeydir ve geri kalanı ise hızlı geçici kesmelerdir.


0

Testinizdeki değişkenlerinizin hatalarını ayıklamak için mesajların PHPunit varsayılan yolunu şu şekilde kullanabilirsiniz:

$this->assertTrue(false,$your_variable);

-1

Laravel kullanıyorsanız, depolama / günlükler altındaki Laravel günlük dosyasına oturum açmak için info () gibi günlüğe kaydetme işlevlerini kullanabilirsiniz. Dolayısıyla, terminalinizde görünmeyecek, ancak günlük dosyasında görünecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.