28

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

4

10 回答 10

21

添加更多方法:


您可以编写自定义测试侦听器并将其添加到 XML 文件中。在该侦听器中,您可以访问$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只是一个例子,它应该很容易适应)。

在此处引用我自己的博客文章:https : //edorian.github.io/2011-01-19-creating-your-custom-phpunit-output.formats/ 获取 xslt 内容。

于 2011-03-07T09:49:15.473 回答
18

只需添加--log-junit "my_tests_log.xml",然后使用电子表格应用程序(Excel、Numbers、Calc)打开此文件即可查看。你得到你要求的所有信息,你可以按测试执行时间排序。

于 2011-07-21T11:45:01.170 回答
9

如果您不喜欢编写 Testlistener,就像已经建议的那样,您可以使用以下脚本以更易于阅读的格式解析PHPUnit 的 JSON 测试结果:

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"
于 2014-01-26T12:59:09.093 回答
7

当前的许多答案都讨论了如何访问和分析日志文件中的持续时间。我将分享两种方法来修改 phpUnit 版本 3.7.38 中的 CLI 输出(这是 Travis-CI 默认用于 PHP 的),基于 @edorian 的不完整答案


使用自定义打印机覆盖 CLI 输出。我找不到任何打印机文档,但它们似乎受支持。您可以在源代码中查看哪些方法可用。

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"

您也可以使用--printerCLI 选项,但这不能很好地与命名空间配合使用。


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>
于 2015-06-11T17:44:42.327 回答
4

您可以实现自己的测试运行器,例如通过扩展PHPUnit_TextUI_TestRunner并使其收集和打印运行时间。

于 2011-03-04T17:15:58.663 回答
3

我想您可以使用setUpandtearDown方法(分别在每个测试的开始和结束时调用)来:

  • 记录测试前的当前时间,在setUp,
  • 并计算测试花费的时间,以tearDown.


当然,您必须在每个测试类中执行此操作,或者在所有测试类都继承的超类中执行此操作。

于 2011-03-04T17:06:41.717 回答
3

好吧,您可以使用Logging导出执行时间。它不会直接作为结果输出,但您可以编写一个漂亮的报告查看器来输出日志文件的结果(来自 JSON 或 XML)。那应该可以得到你想要的......

于 2011-03-04T17:23:05.197 回答
3

这是一个基于edorians answer的想法的完整示例。在 PHPunit 4 上测试。

创建以下 PHP 类:

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.xml:

<phpunit ..>
    ...
    <listeners>
        <listener class="ProfilingTestListener"></listener>
    </listeners>
    ...
</phpunit>

示例输出:

PHPUnit 4.7.7 by Sebastian Bergmann and contributors.

Test 'FooTest::testFoo              ' ended.    Total time 2.050 s. Test time 0.026 s. 
.Test 'FooTest::testBar             ' ended.    Total time 2.077 s. Test time 1.000 s.
.Test 'FooTest::testBar2            ' ended.    Total time 3.077 s. Test time 0.730 s.
于 2015-10-20T14:25:03.290 回答
1

在我看来,最简单的解决方案是将测试统计数据导出为 json:

$ phpunit --log-json testExport.json

于 2017-09-11T13:00:25.040 回答
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。此外,您可以运行您的测试并正常查看它们的输出......您的终端不会在测试完成之前坐在那里。

于 2015-01-26T16:22:55.883 回答