ことの発端
↑を見て、『あー、できるかもなー』と思ったのでやってみました。
--printerオプションで出力をカスタマイズできる
PHPUnitには--printer
オプションがあります。ドキュメントには
結果を表示するために使うプリンタクラスを指定します。このプリンタクラスは PHPUnit\Util\Printer を継承し、
かつPHPUnit\Framework\TestListener インターフェイスを実装したものでなければなりません。
と記載があります。独自のプリンタークラスを作ればいけそうです。ソースを追っていくとデフォルトでは、PHPUnit\TextUI\DefaultResultPrinter
というクラスを使っているようです。このクラスを拡張したクラスを作ることで、マチカネタンホイザなPHPUnitを作れそうです。
独自プリンタークラス、MatikanetannhauserPrinterを作る
とりあえず、テストに失敗(F)したらむん!
、テスト成功(.)したらえい、
にしてみたいと思います。上記の通りPHPUnit\TextUI\DefaultResultPrinter
の拡張クラスを作りますが、中のコードを見ると、
/**
* A failure occurred.
*/
public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->writeProgressWithColor('bg-red, fg-white', 'F'); // 失敗した時の出力
$this->lastTestFailed = true;
}
/**
* A test ended.
*/
public function endTest(Test $test, float $time): void
{
if ($this->debug) {
$this->write(
sprintf(
"Test '%s' ended\n",
\PHPUnit\Util\Test::describeAsString($test)
)
);
}
if (!$this->lastTestFailed) {
$this->writeProgress('.'); // 成功した時の出力
}
if ($test instanceof TestCase) {
$this->numAssertions += $test->getNumAssertions();
} elseif ($test instanceof PhptTestCase) {
++$this->numAssertions;
}
$this->lastTestFailed = false;
if ($test instanceof TestCase && !$test->hasExpectationOnOutput()) {
$this->write($test->getActualOutput());
}
}
となっており、addFailure
メソッドで失敗時の出力、endTest
でテストが成功している時に成功時の出力をしています。このメソッドをオーバーライドしてしまえば、さくっと作れそうです。
<?php
namespace App\Tests;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\TextUI\DefaultResultPrinter;
use Throwable;
class MatikanetannhauserPrinter extends DefaultResultPrinter
{
/**
* A failure occurred.
*/
public function addFailure(Test $test, AssertionFailedError $e, float $time): void
{
$this->writeProgress('むん! ');
$this->lastTestFailed = true;
}
/**
* A test ended.
*/
public function endTest(Test $test, float $time): void
{
if ($this->debug) {
$this->write(
sprintf(
"Test '%s' ended\n",
\PHPUnit\Util\Test::describeAsString($test)
)
);
}
if (!$this->lastTestFailed) {
$this->writeProgress('えい、');
}
if ($test instanceof TestCase) {
$this->numAssertions += $test->getNumAssertions();
} elseif ($test instanceof PhptTestCase) {
++$this->numAssertions;
}
$this->lastTestFailed = false;
if ($test instanceof TestCase && !$test->hasExpectationOnOutput()) {
$this->write($test->getActualOutput());
}
}
}
これでプリンタークラスは完成しました。今回、赤文字で失敗表示されるのがちょっと微妙だったので、writeProgressWithColor
からwriteProgress
に変更しました。なお、composer.jsonのautoload-dev
にtestsディレクトリがApp\Tests
になるようにオートロード設定しています。
プリンターを設定してマチカネタンホイザにする
独自プリンタークラスができたので、vendor/bin/phpunit --printer "App\Tests\MatikanetannhauserPrinter"
と実行すればマチカネタンホイザになりますが、毎回プリンター指定はめんどくさいので、設定を変更して独自プリンターを使うように変更します。
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
- convertDeprecationsToExceptions="false">
+ convertDeprecationsToExceptions="false"
+ printerClass="App\Tests\MatikanetannhauserPrinter">
<!-- 以下略 -->
phpunit
タグにprinterClass
属性を設定することで、デフォルトでこのクラスを使うようになります。
では実行してみましょう。適当にテストクラスを作ります。
<?php
namespace App\Tests;
use PHPUnit\Framework\TestCase;
class SomeTest extends TestCase
{
public function testHoge()
{
$this->assertTrue(true);
}
public function testFoo()
{
$this->assertTrue(true);
}
public function testBuzz()
{
// むん!にしたいのでわざと失敗させます。
$this->assertFalse(true);
}
}
あとは、いつも通りコマンドを叩きます。
% vendor/bin/phpunit
Cannot load Xdebug - it was already loaded
PHPUnit 9.5.16 by Sebastian Bergmann and contributors.
えい、えい、むん! 3 / 3 (100%)
Time: 00:00.011, Memory: 6.00 MB
There was 1 failure:
1) App\Tests\SomeTest::testBuzz
Failed asserting that true is false.
/Users/user/Project/tests/SomeTest.php:21
FAILURES!
Tests: 3, Assertions: 3, Failures: 1.
はい。できました。