ようへいの日々精進XP

よかろうもん

PHPUnit のテスト結果を人間に優しい感じで出力する

モチベーション

特に何もオプションを指定しない場合の PHPUnit の結果があまりにも人間に対して素っ気ない感じがしたので、テスト結果っぽい感じの出力が得られないものかを調べていた。

世の中の人たちはあの素っ気ない感じで満足されているのかと諦めかけていたころ、PHPUnit のドキュメントに貼られたリンクに気付いた。

Plugins for PHPUnit – The PHP Testing Framework

以下のリンク。

PHPUnit xslt · GitHub

この XSLT Template を噛ませば、あら素敵、テスト結果の出力がお客様が喜びそうな解りやすい感じで出力されるぢゃありませんか。

ということで

引き続き

github.com

こちらの sample を利用する。

シンプルなテスト結果

素っ気ないというとあれだけど、シンプルな出力で個人的には嫌いではない。

# php phpunit.phar tests
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

...F...                                                             7 / 7 (100%)

Time: 1.43 seconds, Memory: 12.50MB

There was 1 failure:

1) CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23

FAILURES!
Tests: 7, Assertions: 7, Failures: 1.

F は失敗したテストケースであることは何となく判る。ちなみに、.F 以外にも以下のようなステータスがある。

ステータス 意味
.(ドット) テスト成功
F テスト失敗
E テストが危険としてマーク
S テストをスキップした
I テストが未実装

ログ出力

ドキュメント を読んでいるとテスト結果を XML フォーマットでログ出力することが出来るとのこと。

# php phpunit.phar tests --log-junit post_build/result.xml
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

...F...                                                             7 / 7 (100%)

Time: 2.27 seconds, Memory: 12.50MB

There was 1 failure:

1) CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23

FAILURES!
Tests: 7, Assertions: 7, Failures: 1.

上記のように --log-junit オプションをつけてテストを起動すると JUnit XML フォーマットでテスト結果を出力してくれる。

以下のような内容になる。

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="tests" tests="7" assertions="7" failures="1" errors="0" time="0.004735">
    <testsuite name="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" tests="4" assertions="4" failures="1" errors="0" time="0.002838">
      <testcase name="test_add" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="6" assertions="1" time="0.000586"/>
      <testcase name="test_sub" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="11" assertions="1" time="0.000567"/>
      <testcase name="test_mul" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="16" assertions="1" time="0.000622"/>
      <testcase name="test_div" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="21" assertions="1" time="0.001063">
        <failure type="PHPUnit_Framework_ExpectationFailedException">CalcTestCase::test_div
Failed asserting that 3 matches expected 2.

/opt/codebuild/tests/CalcTest.php:23
</failure>
      </testcase>
    </testsuite>
    <testsuite name="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" tests="3" assertions="3" failures="0" errors="0" time="0.001896">
      <testcase name="testCanBeCreatedFromValidEmailAddress" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="12" assertions="1" time="0.000612"/>
      <testcase name="testCannotBeCreatedFromInvalidEmailAddress" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="20" assertions="1" time="0.000830"/>
      <testcase name="testCanBeUsedAsString" class="EmailTestCase" file="/opt/codebuild/tests/EmailTest.php" line="27" assertions="1" time="0.000454"/>
    </testsuite>
  </testsuite>
</testsuites>

うむ、冒頭の .F の方が人間には解りやすいかもしれぬ。

phpunit.xslt を噛ますといい感じになる

再掲。

PHPUnit xslt · GitHub

前述の XML にこの XSLT を噛ましてあげると下図のように人間に解りやすい感じの出力になる。

f:id:inokara:20170917221241p:plain

具体的には以下のように XML ファイルの 2 行目に phpunit.xslt へのパスを指定してあげる。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://gist.githubusercontent.com/jrfnl/3c28ea6d9b07fd48656d/raw/aaeb0b879647b1cf1dbfd461a2c4a8e292be738d/phpunit.xslt"?>
<testsuites>
  <testsuite name="tests" tests="7" assertions="7" failures="1" errors="0" time="0.004735">
    <testsuite name="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" tests="4" assertions="4" failures="1" errors="0" time="0.002838">
      <testcase name="test_add" class="CalcTestCase" file="/opt/codebuild/tests/CalcTest.php" line="6" assertions="1" time="0.000586"/>
...

もう少し踏み込んで

このログを HTML に変換して、手元のブラウザでお手軽に見ることが出来るようになれば、もっと人間に優しくなるような気がしたので PHP を使って HTML に変換するスクリプトを作ってみた。

<?php

$filename = 'result.xml';

if (! file_exists($filename)) {
    echo "$filename は存在していません." . "\n";
    exit(1);
}

$xsl = new DOMDocument();
// 事前に https://gist.githubusercontent.com/jrfnl/3c28ea6d9b07fd48656d/raw/aaeb0b879647b1cf1dbfd461a2c4a8e292be738d/phpunit.xslt からダウンロード
$xsl->load("phpunit.xslt");
$xml = new DOMDocument();
// テスト結果
$xml->load("result.xml");

$proc = new XsltProcessor();
$proc->importStylesheet($xsl);
$result_html = $proc->transformToXML($xml);
file_put_contents("result.html", $result_html);

このスクリプトを実行すると result.html が出力される。

f:id:inokara:20170917222709p:plain

何件のテストを実施して、何件のテストが Failure になっているのかが一目瞭然、Failure の原因についても個人的に見易い気がする。

以上

メモでした。