Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?
@KEINOS

PHPUnit でエラー時に任意のメッセージをテスト結果に表示させる

PHPUnit でテストが失敗した時に任意のメッセージを表示させたい。あと fail() メソッドで強制的に失敗させた場合など。

しかも php.iniphpunit.xml をいじらず、手軽に。

phpunit エラー時 メッセージ 任意 表示」で Qiita 記事に絞ってググってみたのですが、タイトルからピンポイントでわかる記事がなかったので、自分のググラビリティとして。

TL; DR

すべてのアサーションの最後の引数は、エラー時のメッセージが指定できるようになっています。

assertTrue()の場合の例
assertTrue(bool $condition[, string $message = ''])
class SampleTest extends TestCase
{
    public function testForceFail()
    {
        $result = false;
        $message = '失敗しちゃった。てへ';
        $this->assertTrue($result, $message);
    }
}

アサーションではありませんが、わざと失敗にする、つまり強制的にエラーにする fail() メソッドにもメッセージが指定できます。

fail()メソッド
fail([string $message = ''])
class SampleTest extends TestCase
{
    public function testForceFail()
    {
        if (true) {
            $this->fail('失敗しちゃった。てへ');
        }
    }
}

TS; DR

PHP に限らず、Bash、 Python、 Docker などでコツコツと作った「俺様スクリプト集」があります。いずれも shebang 付きなので、ファイル名を指定するだけで単体コマンドとして動作します。

イメージとしてはこんな感じのコマンド(スクリプト)です。正常終了時は、実行ステータスを "0"、失敗した場合は実行ステータス "1" で終了します。

コマンドの動作例(実装言語は謎)
$ /Regulation/REG-000 'Hello World!'
$ echo $?
0
$ /Regulation/REG-000 'Hell World!'
NG (Bad argument. Must be 'Hello World!'. Given: Hell World!)
$ echo $?
1

こういった、コマンドの動作テストには Bash の Unit Test で有名な batsBash Automated Testing System)を使うのが一般的だと思います。

しかし、なぜか PHPUnit を使いたかったのです。しかも、久しぶりの PHP と PHPUnit だったので色々と忘れてました。

ググってみたのですが、タイトルからピンポイントの記事がありません。それっぽい記事を開いても、「"phpunit.xml" に display_errorsdisplay_startup_errors を入れろ」とあったり、「"php.ini" をいじれ」といった記事が大半でした。

PHP のシンタックス・エラーとかでなく、普通にテスト失敗時にオリジナル(任意)のコメントを表示させたいだけなのです。

「エラー時にメッセージを表示させるだけに、そこまでせんといかんのか」と PHPUnit を使うのを諦めそうになったところ、普通に PHPUnit 公式のドキュメントに記載がありました。そして普通に引数に渡せばよかったのでした・・・

assertTrue()

assertTrue(bool $condition[, string $message = ''])

$conditionfalse の場合にエラー $message を報告します。

実際には、PHPUnit のDocker のコンテナにマウントしていますが、ローカルでもこんな感じです。

ディレクトリ構成
$ tree /Regulation
.
├── REG-000
├── REG-001
├── REG-002
├── REG-003
├── tests
│   ├── REG-000_Test.php
│   ├── REG-001_Test.php
│   ├── REG-002_Test.php
│   ├── REG-003_Test.php
│   ├── autoload.php
│   └── phpunit.xml
└── run_tests.sh
REG-000コマンドの動作例(実装言語は謎)
$ /Regulation/REG-000 'Hello World!'
$ echo $?
0
$ /Regulation/REG-000 'Hell World!'
NG (Bad argument. Must be 'Hello World!'. Given: Hell World!)
$ echo $?
1
run_tests.sh
#!/usr/bin/env bash

phpunit --configuration /Regulation/tests/phpunit.xml /Regulation/tests
REG-000_Test.php(わざとテストを失敗させて動作確認)
<?php
namespace REG\Tests;

class Reg000Test extends TestCase
{
    public function testReg000()
    {
        $message  = 'Hell World!';
        $lastline = exec("/Regulation/REG-000 '${message}'", $output, $return_var);
        $this->assertTrue($return_var === 0, $lastline);
    }
}
phpunit.xml
<?xml version="1.0" encoding="UTF-8" ?>
<phpunit bootstrap="autoload.php">
    <testsuites>
        <testsuite name="Test suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
</phpunit>
autoload.php
<?php
namespace REG\Tests;

// これは Docker phpunit/phpunit の場合の autoload 先ですが、
// 適宜自分の composer の autoload.php のパスを指定してください。
require_once('/tmp/vendor/autoload.php');

class TestCase extends \PHPUnit\Framework\TestCase
{
    // Warning も確実にエラーとして扱うようにする
    public function setUp()
    {
        set_error_handler(function ($errno, $errstr, $errfile, $errline) {
            $msg  = 'Error #' . $errno . ': ';
            $msg .= $errstr . " on line " . $errline . " in file " . $errfile;
            throw new RuntimeException($msg);
        });
    }
    public function tearDown()
    {
        restore_error_handler();
    }
}
テストの実行例(わざとテストを失敗させて、メッセージを確認)
$ # テスト実行
$ cd /Regulation
$ ./run_tests.sh
PHPUnit 6.5.13 by Sebastian Bergmann, Julien Breux (Docker) and contributors.

F                                                                   1 / 1 (100%)

Time: 250 ms, Memory: 4.00MB

There was 1 failure:

1) REG\Tests\Reg000Test::test_Reg000
NG (Bad argument. Must be 'Hello World!'. Given: Hell World!)
Failed asserting that false is true.

/Regulation/tests/REG-000_Test.php:13

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
$ 
$ echo $?
1

一応、正しいテストも。

REG-000_Test.php(今後は正しいテスト)
<?php
namespace REG\Tests;

class Reg001Test extends TestCase
{
    public function testReg000()
    {
        // 正しいデータでのテスト
        $message  = 'Hello World!';
        $lastline = exec("/Regulation/REG-000 '${message}'", $output, $return_var);
        $this->assertTrue($return_var === 0, $lastline);

        // 間違ったデータでのテスト
        $message  = 'Hell World!';
        $lastline = exec("/Regulation/REG-000 '${message}'", $output, $return_var);
        $this->assertTrue($return_var === 1, $lastline);
    }
}
テストの実行(今度はパス)
$ cd /Regulation
$ ./run_tests.sh
PHPUnit 6.5.13 by Sebastian Bergmann, Julien Breux (Docker) and contributors.

.                                                                   1 / 1 (100%)

Time: 215 ms, Memory: 4.00MB

OK (1 test, 2 assertions)
$ 
$ echo $?
0
動作確認済み環境情報
$ # OS(macOS Mojave)
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.4
BuildVersion:   18E226

$ # PHP バージョン
$ php -v
PHP 7.1.23 (cli) (built: Feb 22 2019 22:08:13) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

$ # PHPUnit バージョン
$ phpunit --version
PHPUnit 6.5.13 by Sebastian Bergmann, Julien Breux (Docker) and contributors.

$ # Composer バージョン
$ composer --version
Composer version 1.7.2 2018-08-16 16:57:12
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?