PHPUnit の使い方

NEW
2021/09/12

PHP_CodeSniffer や PHPStan などで、コードの文法的な正しさは確認できますが、 そのコードが本当に正しい動作を行っているかどうかを確認するためには、やはり最終的には動作させてみるしかありません。

PHPUnit とは?

PHPUnit は、PHPのテストフレームワークです。 その名前からわかる通り、基本的には単体テスト(UnitTest)に使用するためのものです。 プログラムというのは、分割統治法によるアプローチによって、小さく小さく分割され、その分割されたものが統合されることで、最終的に1つのアプリケーションとして機能しています。 単体テストとは、その小さく小さく分割されたその1つ1つをテストするという意味です。 PHPで言えばそれは、1つ1つのクラス、1つ1つのメソッドをテストするということです。

PHPUnit のインストール

さっそくですがインストールしていきましょう。

Composer でインストールする

PHPUnit をインストールする方法はいろいろありますが、Composer を使っている場合は Composer を使ってインストールするのが楽だと思います。 Composer を使って PHPUnit をインストールするには、下記のコマンドを実行するだけです。 基本的には開発環境で使うツールだと思うので、--dev オプションを付けておきましょう。 Composer の使い方がわからないという方は、まずは「Composer 再入門」を参考にしてください。

php composer.phar require --dev "phpunit/phpunit"

インストールできたか確認する

PHPUnit をインストールすると、phpunit コマンドが使えるようになっていますので、使用できるか確認してみましょう。 実行ファイルは ".\vendor\bin\" ディレクトリにあります。

.\vendor\bin\phpunit -h

注意:XAMPP を使用している方へ

XAMPP にはデフォルトで古いバージョンの PHPUnit が含まれていて、しかも PATH が通った状態になっています。 そのため、コマンド名だけで実行すると、XAMPP に入っている方の古い PHPUnit が動きますので注意してください。 Composer でインストールした方の PHPUnit を動かすには ".\vendor\bin" が必要です。

# XAMPP の場合、phpunit とだけ入力すると、"C:\xampp\php\phpunit.bat" が動くので注意
phpunit -h

テストの書き方

テストを書くにはいくつかルールがあります。

  • Hoge という名前のクラスのテストは、HogeTest という名前のクラス(テストクラス)に記述します。
  • テストクラスは、PHPUnit\Framework\TestCase を継承します。
  • テストの内容は、test から始まる名前の public メソッド(テストメソッド)に記述します。
    ※ あるいは、@test アノテーションをメソッドのコメント部で使用します。
  • テストメソッドの中で assertSame() のようなアサーションメソッドを使用して、期待される値と実際の値が等しいことを確かめます。
PHPファイル
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;

final class HogeTest extends TestCase
{
	public function testHogeHoge(): void
	{
		$stack = [];
		$this->assertSame(0, count($stack));
	}
}

アサーションメソッド

アサーションメソッドとは、テストしたいことが、正しいかどうかを判定するためのメソッドです。 テストメソッドの中で、アサーションメソッドを呼び出していく形で、テストを作成します。 アサーションメソッドのメソッド名は全て assert から始まります。

どんなメソッドがあるかは、ここでは記載しません。 あまりにも大量にありますので、公式のドキュメントを見てもらった方が良いと思います。

Expected と Actual

PHPUnit の実行結果や、アサーションメソッドの引数の名前で、Expected と Actual という2つの単語がよく登場します。 Expected が期待される値、Actual が実際の値を表します。 アサーションメソッドの引数を指定する際には、この2つの単語の意味をちゃんと理解して、間違えないように注意しましょう。

setUp() と tearDown()

各テストメソッドが呼ばれる際、その前処理と後処理を共通化したい場合、PHPUnit では setUp()tearDown() というメソッドが用意されています。 このメソッドと同じ名前のメソッドをテストクラスに定義すると、各テストメソッドが呼ばれる際に自動的に呼んでくれます。 setUp() が前処理、tearDown() が後処理です。

PHPファイル
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;

final class HogeTest extends TestCase
{
	public function setUp(): void
	{
		// 前処理
	}

	public function testHogeHoge(): void
	{
		$stack = [];
		$this->assertSame(0, count($stack));
	}

	public function tearDown(): void
	{
		// 後処理
	}
}

基本的な使い方

さっそく使ってみましょう。

単一のファイルを実行する

1つのファイルを実行する場合は、実行したいファイル名を指定します。 指定できるのは1つだけです。

".\tests\HogeTest.php" ファイルを実行する場合
.\vendor\bin\phpunit .\tests\HogeTest.php

複数のファイルを実行する

複数のファイルを実行する場合は、実行したいディレクトリ名を指定します。 指定できるのは1つだけです。

".\tests" ディレクトリを実行する場合
.\vendor\bin\phpunit .\tests

出力内容に色を付ける

デフォルトでは出力内容には色が付いていないので白黒な画面になってしまうと思われますが、この出力内容に色を付けることができます。 色を付けるには --colors オプションを付けます。 --colors オプションで指定できる値は下記の3つです。

  • never:出力を色分けしません。これは、--colors オプション自体が未指定の場合のデフォルトです。
  • auto:ターミナルが色をサポートしていない場合や、出力をコマンドにパイプしたりファイルにリダイレクトしたりする場合を除き、出力に色を使います。 --colors オプションでだけを指定して、値を何も指定しなかった場合は、auto を指定していることと同じになります。
  • always:ターミナルが色をサポートしていない場合や、 出力をコマンドにパイプしたりファイルにリダイレクトしたりする場合も含めて、常に出力に色を使います。
# 値を省略した場合は --colors=auto と同じ
.\vendor\bin\phpunit --colors .\tests
出力内容
PHPUnit 9.5.9 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:00.012, Memory: 4.00 MB

OK (2 tests, 10 assertions)

エラーが発生した時点で停止させる

デフォルトでは、どこかのテストでエラーが発生しても、全てのテストの実行が終了するまで止まりません。 どこかのテストでエラーが発生するということは、それを使っている他の個所もまたエラーになるということです。 エラーが1つでも見つかったのなら、すぐにその時点で実行を止めて、エラーの個所を教えて欲しいと感じるでしょう。 全てのテストが終わるまで待っているのは、かなりの時間のロスになります。

注意しないといけないのは、最初に発生したエラーの発生個所がエラーの本当の原因ではない可能性があるということです。 あくまでテストの実行順的に最初に発生したというだけなので、エラーの本当の原因はさらに別の個所で発生したエラーである、という可能性があります。

エラーが発生した時点で停止させるには、--stop-on-failure オプションを使用します。

.\vendor\bin\phpunit --stop-on-failure .\tests

ブートストラップ用のPHPファイルを指定する

CakePHP や Laravel などのPHPフレームワークを使用しているアプリケーションのコードを PHPUnit でテストしたいとしましょう。 フレームワークは、アプリケーションの実行に必要な様々な処理を、初期化処理として自動的に行ってくれています。 言い換えれば、そのアプリケーションのコードは、単体では正しく動作しないということです。 フレームワークと組み合わせて初めて正しく動作するのです。

そのような何かに依存したコードを PHPUnit 上で動かすためには、その依存しているものが行っている前処理と同じ処理を、テストの前に実行しておく必要があります。

PHPUnit のテストの前に実行される処理は、PHPファイルで、--bootstrap オプションで指定できます。

テストの前に ".\tests\bootstrap.php" ファイルを実行する場合
.\vendor\bin\phpunit --bootstrap=.\tests\bootstrap.php .\tests

XML設定ファイル

PHPUnit では、コマンドのパラメーターだけでも細かな設定ができるのですが、さすがに全てを指定するのは大変です。 コマンドよりも設定ファイルを使用した方が良いでしょう。

設定ファイルを使用する

設定ファイルを使用する方法は2つあります。

--configuration オプションで指定する

1つ目の方法は、--configuration オプションで使用したい設定ファイルを指定することです。 複数の設定ファイルを使用して、設定を切り替えたい場合などには便利かもしれません。 --configuration オプション には、エイリアス(別名) -c オプションがあります。

.\vendor\bin\phpunit -c .\custom_phpunit.xml

デフォルトの設定ファイルを使用する

2つ目の方法は --configuration オプションは指定せず、デフォルトの設定ファイルを使用する方法です。

--configuration オプションを指定しない場合(つまりデフォルト)、 PHPUnit は現在のディレクトリから設定ファイルを探します。 この時に探されるファイルの名前は、「phpunit.xml」「phpunit.xml.dist」の2つです。 この2つのファイル名のどちらかと一致するファイルが見つかった場合に、そのファイルが自動的に読み込まれます。 もし複数のファイルが見つかった場合は、前述の順番で優先的に読み込まれます。

.\vendor\bin\phpunit

設定ファイルのフォーマット

設定ファイルのフォーマットは XML です。 phpunit タグをルートとし、その中に設定内容のタグを記述していきます。 XMLなのでコメントも書けます。

どんな設定項目があるかは、ここでは記載しません。 あまりにも大量にありますので、公式のドキュメントを見てもらった方が良いと思います。

ここでは簡単な例だけ記載しておきます。

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true">

	<testsuites>
		<testsuite name="all">
			<directory>tests</directory>
		</testsuite>
	</testsuites>

</phpunit>

テストスイート

複数のファイルをテストの対象として指定する方法として、ディレクトリを指定する方法がありました。 しかし、これだとそのディレクトリの全てのテストを毎回実行することになってしまいます。 必ず通るとわかっているテストを毎回実行していては、作業効率があまりよろしくありません。 テストしたい個所とあまり関係がない個所のテストはスキップしたいと考えるでしょう。

PHPUnit では、どのテストをどの順番で実行するかを細かく指定することができます。 その際に使用するのがテストスイートです。

テストスイートを定義する

テストスイートを定義するには、設定ファイル内で、testsuites タグの中に、testsuite タグで定義していきます。 testsuite タグの name 属性でテストスイートの名前を指定できます。 この名前は、テストスイートを実行する際に使用する名前になります。

ファイルを指定する場合は、file タグを使用し、ディレクトリを指定する場合は、directory タグを使用します。

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true">

	<testsuites>

		<!-- 全てのモデル -->
		<testsuite name="model">
			<directory>tests/TestCase/Model</directory>
		</testsuite>

		<!-- お金関係のみ -->
		<testsuite name="money">
			<file>tests/TestCase/Model/MoneyTest.php</file>
			<file>tests/TestCase/Model/CurrencyTest.php</file>
			<directory>tests/TestCase/Controller/Payments</directory>
		</testsuite>

	</testsuites>

</phpunit>

テストスイートの一覧を表示する

定義したテストスイートの一覧は設定ファイルを見てもわかりますが、--list-suits オプションを使用すると一覧表示してくれます。

.\vendor\bin\phpunit --list-suites
出力内容
PHPUnit 9.5.9 by Sebastian Bergmann and contributors.

Available test suite(s):
 - model
 - money

テストスイートを実行する

定義したテストスイートを実行するには、--testsuite オプションで、実行したいテストスイートの名前を指定します。

ちなみに、--testsuite オプションを使用しない場合は、定義している全てのテストスイートが実行されます。 複数のテストスイートで重複しているテストがある場合、そのテストは1度だけ実行されますので、重複は気にしなくても良いでしょう。

テストスイート "money" を実行する
.\vendor\bin\phpunit --testsuite money

グループ

テストスイートでファイルやディレクトリの単位でテスト対象を定義できましたが、 PHPUnit では、さらにもっと細かく、クラスやメソッド単位でテスト対象をグループ化する方法があります。

例えば、バグ管理システム(課題管理システム)のチケット番号を元にテストをグループ化することで、そのバグ(課題)に関するテストだけ実行するといったような使い方ができます。

グループを定義する

グループはアノテーションとして定義します。 アノテーションというのは、PHPのドキュメンテーションコメントに @アノテーション名 引数 形式でコメントを書くことで、メタデータを定義するものです。 PHPDoc などで @param や、@return などが良く使われているので、見慣れているのはないでしょうか。

グループを定義するには、PHPのメソッドやクラスのドキュメンテーションコメントに @group グループ名 の形式で記載するだけです。 簡単に定義できるからと言って、むやみやたらにグループを作っていると、あっという間に管理できなくなるので注意しましょう。

グループのアノテーションは @group の他にも、@author@ticket などがあります。 これらは、@group のエイリアス(別名)ですので、@group と同じように使用できます。

PHPファイル
<?php
use PHPUnit\Framework\TestCase;

/**
 * @group my
 */
class MyTest extends TestCase
{
	/**
	 * @group regresssion
	 * @group bug2204
	 */
	public function testSomething()
	{
	}

	/**
	 * @author hogehoge
	 * @ticket #1234
	 */
	public function testSomethingElse()
	{
	}
}

グループの一覧を表示する

定義したグループの一覧を表示するには、--list-groups オプションを使用します。

.\vendor\bin\phpunit --list-groups
出力内容
PHPUnit 9.5.9 by Sebastian Bergmann and contributors.

Available test group(s):
 - #1234
 - bug2204
 - default
 - hogehoge
 - my
 - regresssion

グループを実行する

定義したグループを実行するには、--group オプションで、実行したいグループの名前を指定します。

グループ "bug2204" を実行する
.\vendor\bin\phpunit --group bug2204

コードカバレッジ解析

PHPUnit でテストを実行したときに、テスト対象のコードのうちどれくらいの割合がテストされたかというのが分かります。

PHPUnit のコーディングカバレッジ解析を使用するためには、別途 Xdebug のインストールが必要です。 Xdebug のインストール方法と設定方法はここでは記載しません。 「Xdebug の使い方」を参考にしてください。

テスト対象のコードを指定する

コードカバレッジを出力するには、まずテスト対象のコードがどこにあるか指定する必要があります。 テストコードの場所ではなく、実際のソースコードの場所です。 指定する方法は2つあります。

--coverage-filter オプションで指定する

1つ目の方法は、--coverage-filter オプションで指定することです。

.\vendor\bin\phpunit --coverage-filter .\src

設定ファイルで指定する

2つ目の方法は、設定ファイルで coverage タグで指定する方法です。

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true">

	<testsuites>
		<testsuite name="all">
			<directory>tests</directory>
		</testsuite>
	</testsuites>

	<coverage>
		<include>
			<directory>src</directory>
		</include>
	</coverage>

</phpunit>

カバレッジレポートをHTMLで出力する

カバレッジレポートをHTMLで出力するには、--coverage-html オプションで出力先ディレクトリを指定します。 指定したディレクトリの中に、カバレッジレポートがHTMLファイルとして出力されます。

HTMLで出力する --coverage-html オプションの他にも、テキストとして出力する --coverage-text オプションや、XMLファイルとして出力する --coverage-xml オプションなどもあります。

設定ファイルでテスト対象のコードを指定し、"coverage" ディレクトリに出力する場合
.\vendor\bin\phpunit --coverage-html coverage

Composer スクリプトとして登録する

設定ファイルがあるとはいえ、コマンドを毎回入力するのは面倒に感じてくると思います。 特に、ここまでの説明で散々繰り返し記載してきた ".\vendor\bin" を記述するのが面倒に感じてくると思います。 そこで、コマンドを Composer スクリプトとして登録しておくと、入力の手間が少なくなって便利です。 Composer スクリプトでは、 ".\vendor\bin" に PATH が通っているので、".\vendor\bin" を入力する必要はありません。 Composer スクリプトの使い方がわからないという方は、「Composer 再入門(その2:スクリプト)」を参考にしてください。

composer.json
{
	"name": "hoge/hoge",
	"require-dev": {
		"phpunit/phpunit": "^9.5"
	},
	"scripts": {
		"test": "phpunit"
	}
}
登録したスクリプト test を実行する
php composer.phar test

色がちゃんとつかない場合

Composer スクリプトから実行した場合に出力内容に色を付ける場合、--colors オプションを付けていても、色がちゃんとつかない場合があります。 設定ファイルで colors="true" を指定していも色がちゃんと付きません。 そもそも設定ファイルの colors 属性は xs:boolean 型なので、truefalse のどちらかしか指定できません。 その場合は、--colors オプションの値に always を指定してみましょう。

composer.json
{
	"name": "hoge/hoge",
	"require-dev": {
		"phpunit/phpunit": "^9.5"
	},
	"scripts": {
		"test": "phpunit --colors=always"
	}
}

参考サイト

関連記事

プログラムを書いていると気になるのがコードの読みやすさです。複数人で開発している場合などは特にコードの読みやすさは重要です。PHP_CodeSniffer とは?PHP_CodeSniffer は、PHPのコードがちゃんとコーディング規約に沿って記述されているか検査したり、コーディング規約に違反している個所を自動的に修正してくれるツールです。コードをクリーン ...
PHPのコードを実行する前に、バグがあるかどうか調べられると便利だとは思いませんか?PHPはスクリプト言語ですので、いくら文法的に正しいコードであっても、実際に実行させるまでバグか発生するかどうかわからないという、スクリプト言語であるが故の本質的な問題を抱えています。C や Java など他のコンパイル言語ではコンパイル時にエラーになるようなコードであっても ...
PHPでの開発効率を向上させるために、PHP自体に機能を追加するという方法があります。Xdebug とは?Xdebug は、PHPでの開発効率を向上させるためのさまざまな機能を提供してくれるPHPの拡張機能(エクステンション)です。Xdebug でできることは下記の6つです。ステップ実行:スクリプトの実行中にIDEまたはエディターでコードをステップ実行開発ヘ ...
もはやPHPで開発を行う際に、使用していないプロジェクトは探すのが大変なぐらいスタンダードな存在となった Composer ですが、昨年めでたく 2.0 になったということで、改めて少しまとめてみます。今更とか言っちゃダメです。Composer とは?Composer は、PHPの依存関係管理のためのツールです。世界中のエンジニアが作成してくれたライブラリ( ...

記事検索

最新記事

RSSフィード