有没有办法用PHPUnit打印每个测试的执行时间?
答案 0 :(得分:20)
添加更多方法:
您可以撰写custom Test listener和add it to the XML file。在该听众中,您可以访问$testResult->time()
。 phpunit.xml中的一些行和一个10行的PHP类。没那么麻烦。
class SimpleTestListener implements PHPUnit_Framework_TestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test '%s' ended and took %s seconds.\n",
$test->getName(),
$test->time()
);
}
}
如果您仍然生成junit.xml(对于CI或创建代码覆盖率),所有数字都在那里,并且使用简单的XSLT可以使它们更具可读性。
示例junit.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="DemoTest" file="/home/edo/foo.php" tests="2" assertions="2" failures="1" errors="0" time="0.007727">
<testcase name="testPass" class="DemoTest" file="/home/edo/foo.php" line="4" assertions="1" time="0.003801"/>
<testcase name="testFail" class="DemoTest" file="/home/edo/foo.php" line="8" assertions="1" time="0.003926">
<failure type="PHPUnit_Framework_ExpectationFailedException">DemoTest::testFail
Failed asserting that <boolean:false> is true.
/home/edo/foo.php:9
</failure>
</testcase>
</testsuite>
</testsuites>
并进行如下转换:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>Tests</h1>
<xsl:for-each select="testsuites/testsuite">
<h2><xsl:value-of select="@name"/></h2>
<ul>
<xsl:for-each select="testcase">
<li>
<xsl:value-of select="@name"/> : <xsl:value-of select="@time"/>
<xsl:if test="failure">
<b>Failed !</b>
<i><xsl:value-of select="*"/></i>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
你得到的行显示:<li>testPass : 0.003801</li>
(HTML只是一个例子,应该很容易适应)。
在此处引用我自己的博客文章:http://edorian.github.io/2011-01-19-creating-your-custom-phpunit-output.formats/了解xslt内容。
答案 1 :(得分:15)
只需添加 - log-junit“my_tests_log.xml”,然后使用电子表格应用程序(Excel,Numbers,Calc)打开此文件即可查看。您可以获得所需的所有信息,并且可以按测试执行时间排序。
答案 2 :(得分:9)
如果您不喜欢编写Testlistener,就像已经建议的那样,您可以使用以下脚本以更易于阅读的格式解析PHPUnit's JSON Test Result:
alias phpunit-report-runtime="phpunit --log-json php://stdout \
| awk '\$NF ~ '/,/' && \$1 ~ /\"(test|time)\"/' \
| cut -d: -f2- \
| sed \"N;s/\n/--/\" \
| sed \"s/,//\" \
| awk 'BEGIN{FS=\"--\"}; {print \$2 \$1}' | sort -r \
| head -n 5"
格式为<time in seconds>, <test method>
。示例输出:
$ phpunit-report-runtime
0.29307007789612, "VCR\\Util\\SoapClientTest::testDoRequestHookDisabled"
0.16475319862366, "VCR\\CassetteTest::testRecordAndPlaybackRequest"
0.092710018157959, "VCR\\Util\\SoapClientTest::testDoRequest"
0.031861782073975, "VCR\\LibraryHooks\\SoapTest::testShouldInterceptCallWhenEnabled"
0.026772022247314, "VCR\\LibraryHooks\\AbstractFilterTest::testRegisterAlreadyRegistered"
答案 3 :(得分:6)
当前的许多答案都讨论了如何访问和分析日志文件中的持续时间。我将分享两种方法来修改phpUnit版本3.7.38中的CLI输出(这是Travis-CI默认使用的PHP),基于@ edorian的incomplete answer构建。
使用自定义打印机覆盖CLI输出。我找不到任何打印机文档,但似乎支持它们。您可以在source code中查看哪些方法可用。
class TestDurationPrinter extends PHPUnit_TextUI_ResultPrinter
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test '%s' ended and took %s seconds.\n",
$test->getName(),
$time
);
}
}
然后将这些行作为属性添加到phpunit
文件中的phpunit.xml
:
printerFile="path/to/TestDurationPrinter.php"
printerClass="TestDurationPrinter"
您也可以使用--printer
CLI选项,但这与命名空间无关。
您可以通过实现PHPUnit_Framework_TestListener
接口(这与打印机使用的接口相同),通过TestListener添加到CLI输出,而不是覆盖它。这仍然会打印.
,S
和F
,因此如果您愿意,请务必考虑到这一点。
class TestDurationListener implements PHPUnit_Framework_TestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test '%s' ended and took %s seconds.\n",
$test->getName(),
$time
);
}
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
}
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function startTest(PHPUnit_Framework_Test $test)
{
}
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
}
在3.8及更高版本中,可以扩展PHPUnit_Framework_BaseTestListener
,以便您只定义要覆盖的方法。
class TestDurationListener extends PHPUnit_Framework_BaseTestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test '%s' ended.\n", $test->getName());
}
}
要包含新的侦听器,请将这些行添加到phpunit.xml
文件中:
<listeners>
<listener class="TestDurationListener" file="path/to/TestDurationListener.php" />
</listeners>
答案 4 :(得分:5)
您可以实施自己的测试运行器,例如扩展PHPUnit_TextUI_TestRunner
并使其收集并打印运行时间。
答案 5 :(得分:3)
我猜您可以使用setUp
和tearDown
方法(分别在每个测试的开头和结尾调用):
setUp
,tearDown
中计算测试时间。
当然,您必须在每个测试类中执行此操作 - 或者在将由所有测试类继承的超类中执行此操作。
答案 6 :(得分:3)
好吧,你可以用Logging导出执行时间。它不会直接输出,但您可以编写一个漂亮的报表查看器来输出日志文件的结果(来自JSON或XML)。那应该能得到你想要的东西......
答案 7 :(得分:2)
这是一个完整的例子,基于编辑回答的想法。在PHPunit 4上测试。
创建以下PHP类:
getCount()
将以下内容添加到您的phpunit.xml:
class ProfilingTestListener extends PHPUnit_Framework_BaseTestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test '%s' ended.\tTotal time %s s.\tTest time %s s.\n",
str_pad($test->toString(), 50),
number_format($test->getTestResultObject()->time(), 3),
number_format($time, 3)
);
}
}
示例输出:
<phpunit ..>
...
<listeners>
<listener class="ProfilingTestListener"></listener>
</listeners>
...
</phpunit>
答案 8 :(得分:1)
在我看来,最简单的解决方案是将测试统计信息导出为json:
$ phpunit --log-json testExport.json
答案 9 :(得分:0)
我喜欢@ adri的回答。它让我开始了这个:
alias phpunittime=" | awk '\$NF ~ '/,/' && \$1 ~ /\"(test|time)\"/' \
| cut -d: -f2- \
| sed \"N;s/\n/--/\" \
| sed \"s/,//\" \
| awk 'BEGIN{FS=\"--\"}; {print \$2 \$1}' | sort -r \
| head"
要使用,您需要配置PHP单元以输出到JSON日志文件。为此,请将phpunit.xml
看起来像这样:
<phpunit>
<logging>
<log type="json" target="/tmp/logfile.json"/>
</logging>
</phpunit>
然后像这样使用:
$ cat /tmp/logfile.json | phpunittime
要查看多于或少于10个时间,例如2或19,最后分别使用-n 2
或-n 19
。
这有什么好处是它没有假设你如何调用/运行phpunit本身(在我的例子中,我使用CakePHP并运行我的命令:Console/cake test app
)。此外,您可以运行测试并正常查看其输出...您的终端不会只是坐在那里直到测试完成。