Есть ли способ проверить вывод STDERR в PHPUnit? - PullRequest
12 голосов
/ 02 декабря 2011

У меня есть класс, который выводит на STDERR, но у меня возникают проблемы с поиском способа заставить PHPUnit проверить его вывод.

Класс PHPUnit_Extensions_OutputTestCase также не работает.

Ответы [ 3 ]

8 голосов
/ 02 декабря 2011

Я не вижу способа буферизовать stderr, как вы можете с помощью stdout, поэтому я бы реорганизовал ваш класс, чтобы переместить вызов, выполняющий фактический вывод, в новый метод. Это позволит вам смоделировать этот метод во время тестирования, чтобы проверить вывод или подкласс с тем, который буферизирует.

Например, скажем, у вас есть класс, который перечисляет файлы в каталоге.

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

Сначала извлеките вызов на echo. Сделайте его защищенным, чтобы вы могли переопределить и / или высмеять его.

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

    protected function output($text) {
        echo $text ;
    }
}

Во-вторых, в вашем тесте либо имитируйте, либо делите на подклассы. Дразнить легко, если у вас простой тест или вы не ожидаете много звонков на 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'
    }
}

Переопределение output для буферизации всех $text во внутреннем буфере оставлено в качестве упражнения для читателя.

6 голосов
/ 02 декабря 2011

Вы не можете перехватить и 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");
    }

}

Вынимает поток stderrи замените его потоком в памяти и прочитайте его обратно в тестовом примере, чтобы увидеть, был ли записан правильный вывод.

Обычно я наверняка скажу: «Ввести путь к файлу в классе»но с STDERR это не имеет никакого смысла для меня, так что это было бы моим решением.

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

.

Time: 0 seconds, Memory: 5.00Mb

OK (1 test, 1 assertion)

Обновление

Подумав, я скажу, чтоможет не сработать что-то вроде errorSteamWriter как класса.

Просто наличие StreamWriter и построение его с помощью new StreamWriter(STDERR); приведут к хорошему тестируемому классу, который можно использовать много раз.цели в приложении без жесткого кодирования какой-то«это то, куда идут ошибки» в классе, который сам по себе и добавляет гибкости.

Просто хотел добавить это как вариант, чтобы избежать «уродливых» тестовых опций:)

2 голосов
/ 27 января 2012

Используйте потоковый фильтр для захвата / перенаправления вывода в STDERR.Следующий пример на самом деле выполняет и перенаправляет на STDOUT, но передает основную идею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...