PHPUnit 打印测试执行时间

发布于 2024-10-20 02:40:25 字数 34 浏览 2 评论 0原文

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

is there a way to print the execution time of each test with PHPUnit?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

向日葵 2024-10-27 02:40:25

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

Just add --log-junit "my_tests_log.xml" and then open this file with spreadsheet application (Excel, Numbers, Calc) to view it. You get all information you ask for, and you can sort by test execution time.

谁人与我共长歌 2024-10-27 02:40:25

要添加更多方法:


您可以编写 自定义测试监听器将其添加到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 <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>

您会得到显示以下行:

  • testPass : 0.003801
  • (HTML 只是一个示例,它应该很容易适应) 。

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

    To add some more ways:


    You can write a custom Test listener and add it to the XML file. In that listener you can access the $testResult->time(). Some lines in your phpunit.xml and a 10 line PHP class. Not too much hassle.

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

    If you generate a junit.xml anyways (for CI or while creating code coverage) all the numbers are there anyways and with a simple XSLT you can make those even more readable.

    Example 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>
    

    and with an transformation like this:

    <?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>
    

    you get lines showing you: <li>testPass : 0.003801</li> (the HTML is just an example, it should be easily adaptable).

    Referencing my own blog post here: https://edorian.github.io/2011-01-19-creating-your-custom-phpunit-output.formats/ for the xslt stuff.

    夜唯美灬不弃 2024-10-27 02:40:25

    如果您不喜欢编写 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"
    

    格式为 <以秒为单位的时间>, <测试方法>。输出示例:

     $ 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"
    

    If you don't like to write a Testlistener, like it was suggested already, you can use the following script to parse the PHPUnit's JSON Test Result in an easier to read format:

    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"
    

    Format is <time in seconds>, <test method>. Example output:

     $ 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"
    
    滴情不沾 2024-10-27 02:40:25

    当前的许多答案都讨论了如何访问和分析日志文件中的持续时间。我将分享两种修改 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.xml 文件中的 phpunit 中:

    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>
    

    Many of the current answers discuss how to access and analyze the duration times in the log file. I will share two ways to modify the CLI output in phpUnit version 3.7.38 (which is what Travis-CI uses for PHP by default), building on @edorian's incomplete answer.


    Use a custom printer to override the CLI output. I can't find any documentation for printers but they appear to be supported. You can see which methods are available in the 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
            );
        }
    }
    

    Then add these lines as attributes to phpunit in the phpunit.xml file:

    printerFile="path/to/TestDurationPrinter.php"
    printerClass="TestDurationPrinter"
    

    You can also use the --printer CLI option but that doesn't play well with namespaces.


    You can add to the CLI output, as opposed to overriding it, with a TestListener by implementing the PHPUnit_Framework_TestListener interface (this is the same interface that printers use). This will still print ., S, and F so be sure to account for that, if you desire.

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

    In version 3.8 and above there is a PHPUnit_Framework_BaseTestListener that can be extended so that you only define the methods you want to override.

    class TestDurationListener extends PHPUnit_Framework_BaseTestListener
    {
        public function endTest(PHPUnit_Framework_Test $test, $time)
        {
            printf("Test '%s' ended.\n", $test->getName());
        }
    }
    

    To include your new listener, add these lines to your phpunit.xml file:

    <listeners>
        <listener class="TestDurationListener" file="path/to/TestDurationListener.php" />
    </listeners>
    
    王权女流氓 2024-10-27 02:40:25

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

    You can implement your own test runner, for example by extending PHPUnit_TextUI_TestRunner and make it collect and print run times.

    仙女山的月亮 2024-10-27 02:40:25

    这是一个基于 edorians 答案的想法的完整示例。在 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.
    

    Here's a complete example based on the idea from edorians answer. Tested on PHPunit 4.

    Create the following PHP class:

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

    Add the following to your phpunit.xml:

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

    Example output:

    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.
    
    把昨日还给我 2024-10-27 02:40:25

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

    • 记录测试之前的当前时间,在setUp中,
    • 并计算测试花费的时间,在tearDown中。

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

    I guess you could use the setUp and tearDown methods (which are called at the beginning and end of each test, respectively) to :

    • Log the current time before the test, in setUp,
    • And calculate the time the test took, in tearDown.

    Of course, you'll have to do this in each one of your test classes -- or in a super-class which will be inherited by all your test classes.

    盛夏已如深秋| 2024-10-27 02:40:25

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

    Well, you can have it export the execution time with Logging. It's not directly outputted as the result, but you could write a pretty report viewer that would output the results of the log file (either from JSON or XML). That should get you what you want...

    汹涌人海 2024-10-27 02:40:25

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

    $ phpunit --log-json testExport.json

    In my opinion, the simplest solution is to export test statistic as json:

    $ phpunit --log-json testExport.json

    我ぃ本無心為│何有愛 2024-10-27 02:40:25

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

    I liked @adri's answer. It got me started on this:

    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"
    

    To use, you'll need to configure PHP unit to output to a JSON log file. To do so, make your phpunit.xml look like this:

    <phpunit>
        <logging>
            <log type="json" target="/tmp/logfile.json"/>
        </logging>
    </phpunit>
    

    Then use like this:

    $ cat /tmp/logfile.json | phpunittime
    

    To see more or less than 10 timings, say 2 or 19, use -n 2 or -n 19, respectively, at the end.

    What's nice about this is it doesn't make assumptions about how you call/run phpunit itself (in my case, I use CakePHP and run my command like this: Console/cake test app). Also, you can run your tests and see their output as normal... your terminal doesn't just sit there until the tests are done.

    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文