PHPユニットテストの実行中にCLIで出力する方法


151

PHPUnitテストを実行するときに、出力をダンプして1つまたは2つのことをデバッグできるようにしたいと考えています。

私は次のことを試しました(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);
    }   
}

結果は次のとおりです。

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

予期された出力がないことに注意してください。

2011年9月19日の時点で、gitリポジトリの HEADバージョンを使用しています。

の出力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

私が間違っていることはありますか、これは潜在的にPHPUnitのバグですか?


1
testOutput()メソッドを呼び出すコードはどこにありますか?
デリックタッカー

あなたは本当に必死に試します(echo、print、print_r、var_dump-基本的にはすべて「出力」です)。通常、テストからの出力に問題はありません。出力バッファリングが有効かどうかを確認できます:php.net/manual/en/function.ob-get-level.php-強制的に「テスト」する最も安全な方法は、例外BTWをスローすることです。
11

3
@DerrickTucker PHPUnitはこれを呼び出しますphpunit /path/to/tests/theTest.php(上記のクラスがファイル内にある場合theTest.php)。
Jess Telford

@hakre ob_get_level()はを返します1。ただし、これは次のコードと矛盾while (ob_get_level() > 0) { ob_end_flush(); }ob_end_clean(): failed to delete buffer. No buffer to delete.ます。好奇心旺盛で好奇心旺盛。
ジェステルフォード2009

1
それはエラーを引き起こしているのはphpunitのコードであると言っています-明らかにphpunits出力の飲み込みがアクティブだからです(しかし、あなたはそれを壊しました)。正確に見ると、関数名も異なります。
hakre

回答:


196

更新

これを実行する別の方法が--verboseコマンドラインオプションよりもはるかに優れていることに気づきました。

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

これにより、--verboseCLIオプションに伴うすべての不要な出力なしに、いつでもコンソールに何かをダンプできます。


他の回答が指摘しているように、次のような組み込みメソッドを使用して出力をテストするのが最善です。

$this->expectOutputString('foo');

ただし、テストケース内からいたずらで一時的なデバッグ出力を確認すると役立つ場合があります。var_dumpただし、ハック/回避策は必要ありません。これは--verbose、テストスイートの実行時にコマンドラインオプションを設定することで簡単に実現できます。例えば:

$ phpunit --verbose -c phpunit.xml

これにより、CLI環境で実行しているときに、テストメソッド内からの出力が表示されます。

参照:PHPUnitのテストの作成-出力のテスト


5
申し訳ありませんが、stderrに書き込むことができませんでした。確かに動作します。fwriteのfile_put_contents('php://stderr', $myDebugVar, FILE_APPEND);メッセージUse of undefined constant STDERR - assumed 'STDERR'があったため、代わりに使用せざるを得ませんでした。
セルジュ

問題は、これがプロセスの分離では機能しないように見えることです。
donquixote 2014年

テストは、そのSTDERRストリーム出力可能性が破棄され、別のプロセスで実行されますよう@donquixote ...驚くべきことではない
rdlowrey

1
STDOUT代わりに使用することもできますSTERR
Chris

2
はい。動作し、と同じように出力するようSTDERRです。PHPUnit 4.5.0Windowsのcmd行で使用しています。echo文は同じ結果を与えるものではありません。echo出力を行いますが、テスト結果が表示された後のみです。fwrite(STDERR, 'string')またはfwrite(STDOUT,'string')同じ結果を生成する:テスト結果が表示される前の出力。
Chris

33

更新:より簡単な回避策fwrite(STDERR, print_r($myDebugVar, TRUE));としての使用については、以下のrdlowreyの更新を参照してください


この動作は意図的なものです(jasonbar指摘したように)。マニュアルの矛盾する状態はPHPUnitに報告ています。

回避策は、予期しない出力が表示されるようにトリガーする、予想される出力が空である(実際には出力がある場合)PHPUnitにアサートさせることです。

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

与える:

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.

出力アサーションがテストされる前に失敗する可能性があるため、テストに使用している他のアサーションを無効にしてください(したがって、出力が表示されません)。


33

使ってみてください --debug

インクルードまたはソースデータファイルへの正しいパスを取得しようとしている場合に役立ちます。


2
これは私にとって正しい答えです。以前の回答で書かれたすべてのfwriteステートメントは、私にはうまくいきませんでした。
キムスタック14

9

これはバグではありませんが、意図的なものです。あなたの最善の策は、ある種のログファイルに書き込み、出力を監視するためにログをテールにすることです。

出力をテストする場合は、これを確認てください。

また:

:PHPUnitは、テストの実行中に出力されるすべての出力を飲み込むことに注意してください。厳密モードでは、出力を発行するテストは失敗します。


1
もしそれが意図的なものだったら、きっとマニュアルにはその例が載っていないでしょう?また、出力自体をテストしようとしません。いくつかの結果を目視するためにそれを使用すると、テストが失敗するはずのないときにテストが失敗します。
Jess Telford

書かれているとおり:私は通常、テストの実行時にエコーアウトする問題はありません。入力をキャッチするいくつかの構成がある可能性があります。
11

1
それが意図的でなかったなら、きっとマニュアルはそれがそうであったと言っていませ
jasonbar 2011

1
だから、ドキュメントの矛盾のようです。@hakreは私と同じ印象を受けた(飲み込まれてはいけない)-ドキュメントのどの部分が正しいですか?
Jess Telford

--disallow-test-output(またはconfファイルにbeStrictAboutOutputDuringTests = "true"がある場合にのみ出力生成テストが失敗する)-ドキュメントには、「たとえば、テストコードまたはテストされたコードのいずれかでprintを呼び出すことによって出力を発行するテスト、このチェックを有効にすると、危険とマークされます。」phpunit.readthedocs.io/en/8.4/risky-tests.html#risky-tests
NULLポインター

7

私はVisualPHPUnitで運が良かったのですが、とりわけ出力を表示するのに役立ちます。

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

TestHelloの結果


うーん、なぜ反対票なの?これは、PHPUnitテストでデバッグ出力をダンプする別の方法としてどのように役立つのですか?
ボブスタイン14

1
私はよ推測誰もこれを実行しようとする場合は、構文エラーが発生しますので、これがdownvotedされます。巨大なもの。
神保

機能を忘れた 今では修正、テスト、カット、貼り付けされています。ありがとう、@ Jimbo
Bob Stein

悲しいことに、それは明らかに、現時点でPHP 7と互換性がありません:「VisualPHPUnitが原因のPHPUnitが利用されているような方法で、この時点での互換性の7をPHPされていないPHPの7は、次のメジャーリリースではサポートされます。」
レオ

6

あなたは本当にあなたの意図について考える必要があります:テストを修正するためにデバッグするときに今情報が必要な場合、テストが壊れたときに再び来週それが必要になります。

これは、テストが失敗したときに常に情報が必要になることを意味しますvar_dump。原因を見つけるためにを追加するのは、あまりにも多くの作業です。むしろ、データをアサーションに入れます。

コードが複雑すぎる場合は、1つのアサーション(カスタムメッセージを使用)が、どこで問題が発生したか、なぜ、どのようにコードを修正するかを知るのに十分なレベルに達するまで分割します。


1
私はあなたが言ったことすべてに100%同意します。PHPUnitを使用して、最終的にGoogleのXML APIの1つを呼び出す統合テストを実行しています。すべての単体テストは(API呼び出しがモックされて)合格しましたが、(ライブAPI呼び出しで)最終的なテストは失敗しました。それはGoogle APIのせいであることが判明しましたが、それまでの間、生のHTTP応答をダンプしたかったのです。
ジェステルフォード

2
ここで概説したことを達成するためにコードをデバッグする必要がある場合はどうでしょうか?
デビッドマイスター

2
これが、ユーザーが何をしたいかを推測する答えが嫌いな理由です。キャッシュがクリアされるのを待つテストがあるので、ここにいます。5秒のキャッシュttlを使用すると、テスト約16秒間ハングしたよう見えます。いいえ、何も問題はありません。キャッシュがタイムアウトするのを待っているだけであることをユーザーに通知したいと思います。人々が質問に答えることができれば、他のユースケースを持つ人々も答えを得るでしょう。
user151841

4

laravel 5では、dump()を使用できます。最後の応答からコンテンツをダンプします。

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

与える


4

phpunitを実行するときに--verboseフラグを使用するだけです。

$ phpunit --verbose -c phpunit.xml 

この方法の利点は、テストコードを変更する必要がないことです。var_dumpの文字列をいつでも出力でき、詳細モードが設定されている場合にのみコンソールに表示されます。

これがお役に立てば幸いです。


3

場合によっては、そのようなものを使用してコンソールに何かを出力することができます

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

ハックだが動作する:デバッグ出力をメッセージとして例外をスローします。

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

収量:

...
There was 1 error:

1) theTest::testOutput
Exception: hello

2

これは、PHPUnit DocsのFixturesについてのものです。

これにより、phpunitテストのライフサイクル中の任意の時点で情報をダンプできます。

__METHOD__以下のコードを出力したいものに置き換えてください

例4.2:使用可能なすべてのテンプレートメソッドを示す例

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

1

TestresultsをHTMLベースで出力します。この場合、コンテンツをフラッシュすると便利です。

var_dump($array);
ob_flush();

2番目のPHPメソッドがあります

flush() 

私は試していません。


1

PHPUnitはで出力を隠していますob_start()。一時的に無効にすることができます。

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

0

このコードが機能するようにソースコード変更する必要があったので、このフォークされたリポジトリの URLをComposerに追加して機能させる必要があります

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でデバッグメッセージを印刷するのに役立ついくつかのメソッドを次に示します。

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

    より実用的な例:

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

    呼び出すsyslog()と、システムログメッセージが生成されます(参照:)man syslog.conf

    注:可能なレベル:LOG_DEBUGLOG_INFOLOG_NOTICELOG_WARNINGLOG_ERR、など

    macOSでは、syslogメッセージをリアルタイムでストリーミングするには、次のコマンドを実行します。

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

    注:stdinSTDERRからPHPスクリプトを読み取る場合、定数は使用できません。これが回避策です。

    注:の代わりにSTDERR、ファイル名を指定することもできます。

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

    注:STDERR定数が定義されていない場合は、このメソッドを使用してください。

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

    注:テストに影響を与えずに最後に何かを印刷する場合は、このメソッドを使用します。

変数、使用ダンプするにはvar_export()、例えば"Value: " . var_export($some_var, TRUE) . "\n"

上記のメッセージを冗長モードまたはデバッグモードでのみ印刷するに、「テストで--debugまたは--verboseがPHPUnitに渡されたかどうかを確認する方法はありますか?」を参照してください。


ただし、出力のテスト自体がテストの一部である場合は、「テスト出力のドキュメントページ」を確認してください。


-1

Laravelを使用する場合、info()などのロギング関数を使用して、storage / logsの下のLaravelログファイルにログを記録できます。そのため、ターミナルには表示されず、ログファイルに表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.