PHPUnit打印测试执行时间

时间:2011-03-04 17:02:49

标签: php phpunit execution-time

有没有办法用PHPUnit打印每个测试的执行时间?

10 个答案:

答案 0 :(得分:20)

添加更多方法:


您可以撰写custom Test listeneradd 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 &lt;boolean:false&gt; 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输出,而不是覆盖它。这仍然会打印.SF,因此如果您愿意,请务必考虑到这一点。

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)

我猜您可以使用setUptearDown方法(分别在每个测试的开头和结尾调用)

  • 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)。此外,您可以运行测试并正常查看其输出...您的终端不会只是坐在那里直到测试完成。