在PHP单元测试执行期间,如何在CLI中输出?

在运行PHPUnit测试时,我希望能够转储输出,以便调试一两个东西。

我已经尝试了以下(类似于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错误?

169042 次浏览

这不是漏洞,而是故意的。最好的方法是写入某种类型的日志文件,并跟踪日志以观察输出。

如果你试图测试输出,检查

另外:

请注意:请注意PHPUnit吞噬所有发出的输出 在测试执行期间。在严格模式下,发射的测试

.输出失败

更新:参见Rdlowrey的更新如下,关于使用fwrite(STDERR, print_r($myDebugVar, TRUE));作为更简单的解决方法


这种行为是有意的(因为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.

一定要禁用用于测试的任何其他断言,因为它们可能在测试输出断言之前失败(因此您将看不到输出)。

您应该认真考虑您的意图:如果您现在在调试以修复测试时需要这些信息,那么当测试中断时,您将在下周再次需要这些信息。

这意味着当测试失败时,你将需要信息总是——而添加var_dump来查找原因是太多的工作。而是把数据放到你的断言中。

如果您的代码过于复杂,那么就将其拆分,直到达到一个断言(带有自定义消息)足以告诉您哪里出错了,为什么出错以及如何修复代码的程度。

更新

刚刚意识到另一种方法来做到这一点,比--verbose命令行选项更好:

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

这让你可以随时将任何东西转储到控制台,而不会出现--verbose CLI选项附带的所有不必要的输出。


正如其他答案所指出的,最好使用内置方法来测试输出,例如:

$this->expectOutputString('foo');

然而,有时调皮一点,看看测试用例中的一次性/临时调试输出是有帮助的。不过,不需要var_dump黑客/变通方法。这可以通过在运行测试套件时设置--verbose命令行选项轻松实现。例如:

$ phpunit --verbose -c phpunit.xml

当在CLI环境中运行时,这将显示测试方法内部的输出。

看到:为PHPUnit编写测试-测试输出

我在VisualPHPUnit上有一些运气,它确实有用地显示了输出。

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

TestHello results

尝试使用--debug

如果您试图获得包含数据文件或源数据文件的正确路径,则此选项非常有用。

我必须修改源代码这段代码的工作,所以你需要添加URL为这个分叉回购的作曲家,这将工作

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

这是从关于装置的PHPUnit文档中截取的。

这应该允许您在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;
}
}
?>

在某些情况下,可以使用类似的东西向控制台输出一些内容

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

在laravel 5中,您可以使用dump(),转储上次响应的内容。

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

给出

我输出我的Testresults基于HTML,在这种情况下,它是有帮助的刷新内容:

var_dump($array);
ob_flush();

还有第二个PHP方法

flush()

我没有试过。

下面是PHPUnit 4.x中用于打印调试消息的几个有用方法:

  • < p > 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");

    Note: The STDERR constant is not available if reading the PHP script from stdin. Here is the workaround.

    Note: Instead of STDERR, you can also specify a filename.

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

    Note: Use this method, if you don't have STDERR constant defined.

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

    Note: Use this method, if you'd like to print something at the very end without affecting the tests.

To dump the variable, use var_export(), e.g. "Value: " . var_export($some_var, TRUE) . "\n".

To print above messages only during verbose or debug mode, see: Is there a way to tell if --debug or --verbose was passed to PHPUnit in a test?


Although if testing the output is part of the test it-self, check out: Testing Output docs page.

恶意的,但有效:抛出异常,并将调试输出作为其消息。

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

收益率:

...
There was 1 error:


1) theTest::testOutput
Exception: hello

只要在执行phpunit)时使用——详细标志。

$ phpunit --verbose -c phpunit.xml

这个方法的优点是你不需要改变测试代码,你可以打印字符串,var_dump或任何你想要的东西,只有当详细的模式被设置时,它才会显示在控制台上。

我希望这能有所帮助。

PHPUnit用ob_start()隐藏输出。我们可以暂时关闭它。

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

如果您使用Laravel,那么您可以使用诸如info()这样的日志函数来记录到存储/日志下的Laravel日志文件。所以它不会出现在终端中,而是出现在日志文件中。

简而言之,phpunit抑制了STDOUT。默认情况下,它会写入STDERR,除非你添加--verbose--debug。你可以做这些事情中的一件:

  • 相反,将调试输出打印到STDERR
  • var_dump你的调试像往常一样,但添加--verbose到phpunit命令行
  • var_dump你的调试像往常一样,但在它下面添加一行ob_flush();
  • 在phpunit中使用正确的命令来测试您在这里要测试的内容

显然,最后一件事是要做的好事,剩下的都是临时的小技巧。

你可以使用PHPunit默认的方式来调试测试中的变量,如下所示:

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

可以使用Symfony\Component\Console\Output\TrimmedBufferOutput,然后像这样测试缓冲的输出字符串:

use Symfony\Component\Console\Output\TrimmedBufferOutput;


//...
public function testSomething()
{
$output = new TrimmedBufferOutput(999);
$output->writeln('Do something in your code with the output class...');
   

//test the output:
$this->assertStringContainsString('expected string...', $output->fetch());
}
这是一个付费产品,但我发现它做得很好:来自Spatie的Ray https://spatie.be/products/ray < / p >

就像这样使用它:

雷(“信息”)

消息将显示在Ray输出窗口中

只需在输出文本后调用ob_flush()即可

示例代码:

    public function testDebugOutputToCli() {
var_dump(new DateTime());
ob_flush();
}

代码和输出截图:

使用ob_flush来回显原本由PHPUnit隐藏的内容的截图

为什么?PHPUnit总是输出缓冲区,所以我们需要在调试时转储缓冲区

我对上面所有的答案都很挣扎,特别是因为所选的答案——如手册所述,使用codecept_debug()--debug——导致了调试输出的巨大浪潮,使我无法使用它。

我像一个好书呆子一样阅读PHPUnit手册,无意中发现了这个,我认为这解释了导致整个PHPUnit问题的原因,而不仅仅是Codeception:

PHPUnit手册,测试输出:“有时你想断言一个方法的执行,例如,产生一个预期的输出(例如通过echo或print)。PHPUnit\Framework\TestCase类使用PHP的Output Buffering特性来提供必要的功能。

这是完全有意义的,并解释了为什么我们看不到输出。PHPUnit正在保存它,以防我们想要检查注释!这就是它在实际测试中应该始终工作的方式,我们当然不希望仅仅因为调用了使用echo的函数就出现随机的东西。

但是当我们调试时,我们只是想马上看到文本,并理解这一切,解决方案是明确的:只需使用ob_flush()按需打印输出缓冲区的内容!

为阅读有趣的手册欢呼三声!

附注:还发现这个提示隐藏在如何显示在phpunit或codeception由朱利安dev.to var_dumps