はじめに
はじめまして株式会社ナイトレイの渡辺です。
現在私が関わっているプロダクトでPHPのユニットテストを導入した際、PHPUnitを利用するにあたって公式ドキュメントを一通り読んだので、この記事では個人的に重要な箇所を備忘録としてまとめます。
💡 本記事で記載されている内容はこちらのドキュメントから引用させていただいております
対象読者
- 少しPHPUnitを使ったことがある
- PHPUnitをもっと上手く使いたい
環境
PHPUnit 9.5.20
内容
PHPUnit 用のテストの書き方
この章では、PHPUnit を使ったテストを書く際の基本的な決まり事や手順を紹介しています。
最低限、PHPUnitでテストを書く上で必要な情報なので一通り目を通すことを推奨します。
https://phpunit.readthedocs.io/ja/latest/writing-tests-for-phpunit.html
フィクスチャ
テンプレートメソッド
テンプレートメソッド setUp()
および tearDown()
は、テストケースクラスのテストメソッドごとに (そして最初にインスタンスを作成したときに) 一度ずつ実行されます。
また、テンプレートメソッド setUpBeforeClass()
および tearDownAfterClass()
が存在します。 これらはそれぞれ、テストケースクラスの最初のテストメソッドの実行前と テストケースクラスの最後のテストの実行後にコールされます。
アンチパターン
Example 4.3 テストスイートの複数テスト間でのフィクスチャの共有
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class DatabaseTest extends TestCase
{
private static $dbh;
public static function setUpBeforeClass(): void
{
self::$dbh = new PDO('sqlite::memory:');
}
public static function tearDownAfterClass(): void
{
self::$dbh = null;
}
}
tearDown()の使い所
tearDown()
を実装する必要があるのはsetUp()
で外部リソース (ファイルやソケットなど) を割り当てた場合のみです。もし setUp()
で単に PHP オブジェクトを作成しただけの場合は、 一般には tearDown()
は必要ありません。
phpunit.xmlについて
beStrictAboutTestsThatDoNotTestAnything="false”
PHPUnit はデフォルトで、何も確かめていないテストを検出します。 このチェックを無効にするには、コマンドラインオプション --dont-report-useless-tests
を使うか、あるいは PHPUnit の XML 設定ファイルで beStrictAboutTestsThatDoNotTestAnything="false"
を設定します。
何もアサーションを実行していないテストは、このチェックを有効にしておくと、 危険であるとマークされます。モックオブジェクトでの例外や、 @expectedException などのアノテーションは、アサーションとみなします。
beStrictAboutOutputDuringTests="true”
PHPUnit は、テストの最中の出力を検出することができます。 このチェックを有効にするには、コマンドラインオプション --disallow-test-output
を使うか、あるいは PHPUnit の XML 設定ファイルで beStrictAboutOutputDuringTests="true"
を設定します。
テストコードあるいは被テストコードの中で、print などで何かを出力している場合に、 このチェックを有効にしておくと、危険であるとマークされます。
**XML 設定ファイルを用いたテストスイートの構成
PHPUnit の XML 設定ファイルを使ってテストスイートを構成することができます。
Example 5.1 で一番シンプルなphpunit.xml
ファイルを示します。これは、tests
ディレクトリを再帰的に探索して *Test.php
というファイルにある *Test
クラスをすべて追加する設定です。
Example 5.1 XML 設定ファイルを用いたテストスイートの構成
<phpunit bootstrap="src/autoload.php">
<testsuites>
<testsuite name="money">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
特定のテストスイートを実行したい場合は、--testsuite
オプションを利用します。
$ phpunit --bootstrap src/autoload.php --testsuite money
PHPUnit latest.0 by Sebastian Bergmann and contributors.
..
Time: 167 ms, Memory: 3.00Mb
OK (2 test, 2 assertions)
-
-configuration
が設定 されていない 場合は、現在の作業ディレクトリからphpunit.xml
あるいはphpunit.xml.dist
を (この順に) 探し、 見つかった場合はそれを自動的に読み込みます。
また以下のように、テストの実行順序を XML 設定ファイルで明示的に指定することもできます。
Example 5.2 XML 設定ファイルを用いたテストスイートの構成
<phpunit bootstrap="src/autoload.php">
<testsuites>
<testsuite name="money">
<file>tests/IntlFormatterTest.php</file>
<file>tests/MoneyTest.php</file>
<file>tests/CurrencyTest.php</file>
</testsuite>
</testsuites>
</phpunit>
不完全なテスト・テストの省略
テストに未完成の印をつける
Example 7.1 では SampleTest
というテストケースクラスを定義しています。 markTestIncomplete()
をテストメソッド内でコールすることで、 このメソッドがまだ完成していないことをはっきりさせます。
Example 7.1 テストに未完成の印をつける
use PHPUnit\Framework\TestCase;
final class SampleTest extends TestCase
{
public function testSomething(): void
{
// オプション: お望みなら、ここで何かのテストをしてください。
$this->assertTrue(true, 'これは動いているはずです。');
// ここで処理を止め、テストが未完成であるという印をつけます。
$this->markTestIncomplete(
'このテストは、まだ実装されていません。'
);
}
}
未完成のテストは、PHPUnit のコマンドライン版テストランナーでは以下のように I
で表されます。
$ phpunit --verbose SampleTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.
I
Time: 0 seconds, Memory: 3.95Mb
There was 1 incomplete test:
1) SampleTest::testSomething
このテストは、まだ実装されていません。
/home/sb/SampleTest.php:12
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 1, Incomplete: 1.
アサーション
利用可能なアサーションメソッドの一覧
この章では、利用可能なアサーションメソッドの一覧が記載されています。
実際にテストを書く中で、どのような時にどのアサーションを使えばいいのかを考えるタイミングがあります。その度にこの章を見返すことで最適なアサーションを選択できるようになります。
https://phpunit.readthedocs.io/ja/latest/assertions.html
アノテーション
@testdox
アジャイルドキュメントを生成する際に使う別の説明を指定します。
@testdox
アノテーションは、クラスにもテストメソッドにも指定できます。
<?php **declare**(strict_types=1);
**use** PHPUnit\Framework\TestCase;
*/**
* @testdox A bank account
*/*
**final** **class** **BankAccountTest** **extends** TestCase
{
*/**
* @testdox has an initial balance of zero
*/*
**public** **function** balanceIsInitiallyZero(): void
{
$this->assertSame(0, $this->ba->getBalance());
}
}
@dataProvider
テストメソッドには任意の引数を渡すことができます。 引数は、データプロバイダメソッド (配列の配列を返すデータプロバイダの使用 の provider()
) から渡されます。 使用するデータプロバイダメソッドを指定するには @dataProvider
アノテーションを使います。
詳細は データプロバイダ を参照ください。
@before
@before
アノテーションを使うと、 テストケースクラス内の各テストメソッドを実行する前に呼ぶメソッドを指定できます。
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class MyTest extends TestCase
{
/**
* @before
*/
public function setupSomeFixtures(): void
{
// ...
}
/**
* @before
*/
public function setupSomeOtherFixtures(): void
{
// ...
}
}
@after
@after
アノテーションを使うと、 テストケースクラス内の各テストメソッドを実行した後に呼ぶメソッドを指定できます。
最後に
私たちの会社、ナイトレイでは一緒に自社開発のWebサービスを盛り上げてくれるエンジニアメンバーを募集しています!
基本的には直接ユーザーと接することのないポジションですが、セールス部門から
「顧客の声」を教えてもらったり、希望すればユーザーとのMTGに参加することも可能です。
モチベーションの高め方はあなた次第。
このような方は是非Wantedlyからお気軽にご連絡ください(もしくはこちらまで recruit@nightley.jp )
✔︎ 自社Webサービスの開発で事業の発展に携わってみたい
✔︎ 自分が開発したサービスで地域活性化に貢献したい
✔︎ 位置情報ビッグデータに興味があり、新しい活用方法を提案したい
✔︎ 地理や地図が好きで仕事中も眺めていたい
一つでも当てはまる方は是非こちらの記事をご覧ください
▼ナイトレイとは?