有没有办法在PHPUnit中测试STDERR输出?

Kev*_*era 12 php phpunit

我有一个输出到的类STDERR,但我找不到让PHPUnit测试其输出的方法.

这堂课,PHPUnit_Extensions_OutputTestCase也没用.

Dav*_*ess 8

我不明白的方式来缓冲stderr,你可以用stdout,所以我会重构类移动完成实际输出到一个新的方法调用.这将允许您在测试期间模拟该方法,以使用缓冲区验证输出或子类.

例如,假设您有一个列出目录中文件的类.

class DirLister {
    public function list($path) {
        foreach (scandir($path) as $file) {
            echo $file . "\n";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,提取呼叫echo.使其受到保护,以便您可以覆盖和/或模拟它.

class DirLister {
    public function list($path) {
        foreach (scandir($path) as $file) {
            $this->output($file . "\n");
        }
    }

    protected function output($text) {
        echo $text ;
    }
}
Run Code Online (Sandbox Code Playgroud)

其次,在测试中模拟或子类化.如果您进行简单的测试或者不期望多次调用,那么模拟很容易output.如果要验证大量输出,则子类化以缓冲输出会更容易.

class DirListTest extends PHPUnit_Framework_TestCase {
    public function testHomeDir() {
        $list = $this->getMock('DirList', array('output'));
        $list->expects($this->at(0))->method('output')->with("a\n");
        $list->expects($this->at(1))->method('output')->with("b\n");
        $list->expects($this->at(2))->method('output')->with("c\n");
        $list->list('_files/DirList'); // contains files 'a', 'b', and 'c'
    }
}
Run Code Online (Sandbox Code Playgroud)

output将所有缓冲$text到内部缓冲区的覆盖作为读者的练习.


edo*_*ian 6

你不能fwrite(STDERR);在phpunit的帮助下拦截测试用例.就此而言,你甚至无法拦截fwrite(STDOUT);,甚至连输出缓冲.

因为我假设你真的不想注入STDERR你的" errorOutputWriter"(因为它没有任何意义让这个类写在别的地方)这是我建议那种小黑客的极少数情况之一:

<?php 

class errorStreamWriterTest extends PHPUnit_Framework_TestCase {

    public function setUp() {
        $this->writer = new errorStreamWriter();
        $streamProp = new ReflectionProperty($this->writer, 'errorStream');
        $this->stream = fopen('php://memory', 'rw');
        $streamProp->setAccessible(true);
        $streamProp->setValue($this->writer, $this->stream);
    }

    public function testLog() {
        $this->writer->log("myMessage");
        fseek($this->stream, 0);
        $this->assertSame(
            "Error: myMessage",
            stream_get_contents($this->stream)
        );
    }

}

/* Original writer*/
class errorStreamWriter {
    public function log($message) {
        fwrite(STDERR, "Error: $message");
    }
}

// New writer:
class errorStreamWriter {

    protected $errorStream = STDERR;

    public function log($message) {
        fwrite($this->errorStream, "Error: $message");
    }

}
Run Code Online (Sandbox Code Playgroud)

它取出stderr流并将其替换为内存流,并在测试用例中读回一个以查看是否写入了正确的输出.

通常,我肯定会说"在课堂中注入文件路径",但这STDERR对我没有任何意义,所以这将是我的解决方案.

phpunit stderrTest.php 
PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 5.00Mb

OK (1 test, 1 assertion)
Run Code Online (Sandbox Code Playgroud)

更新

在给出一些想法之后,我会说没有像errorSteamWriter课时那样思考也可能会有用.

只需拥有一个StreamWriter并构造它就new StreamWriter(STDERR);可以生成一个可测试的类,它可以在应用程序中重复用于很多目的而无需硬编码某种"这就是错误进入类"它自己并增加灵活性.

只是想添加这个作为一个选项,以避免"丑陋"的测试选项:)