最近になってPHPUnitをちゃんと使ってユニットテストを書くようになってきたのですが、まだまだTipsが足りないと感じます。個人的に実践している書き方をいくつか並べてみます。
追記:最初、シェバングと書いていましたが、オプションを渡せる数が決まっていたりOSによっては動かなかったりとあまり便利でないことがわかりました。。phpunit.xmlを書いた方がいいかも。
ちょっとしたテスト → シェルスクリプト化する
PHPUnitは高機能なのですが、いかんせん最初の障壁が高いと思います。とにかく気軽に書きたいなら、シェルスクリプトを作って単独ファイルで実行できるようにするといいです。
#!/bin/sh phpunit --colors *Test.php # ↑オプションを書き並べておく
<?php
class SampleTest extends PHPUnit_Framework_TestCase
{
/**
* @test
*/
function 一足す一は二()
{
$this->assertEquals(2, 1 + 1);
}
// ... テストを書いていく
}
こんな感じでテストを書いておいて、chmod 755 testrunner.shと実行権限を与えておけば、./testrunner.shのように単体で実行することでテストが走るようになります。
別にphpunit SampleTest.phpとphpunitコマンド+テストファイルを直接実行してもいいのですが、phpunitはオプションが長い上、--colors(テスト結果に色を付ける)のような頻繁に使うオプションがデフォルトでoffなので、毎度指定する必要があります。これが面倒なのです。
そこで一番手っ取り早いのがシェルスクリプト化です。使いたいオプションを全部並べておけば、毎回指定しなくてもいいし、設定ファイルの書式を覚えなくてもいいし、コマンド一発で実行できます。小さなライブラリの類だとこの方法が楽チンでしょう。個人的にもよく使っています。
テストを分割したくなる規模 → phpunit.xmlを書く
シェルスクリプトの方法だと、テストの規模が大きくなってくると辛いですね。includeを使って拡張していく手もありますが、もっとエレガントな方法がPHPUnitには用意されています。設定をXMLファイルに書いておくのです。
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
bootstrap="bootstrap.php">
<testsuite name="Sample">
<directory>.</directory>
</testsuite>
</phpunit>
phpunit.xmlがカレントディレクトリに存在する場合、単にphpunitとコマンドを単独で実行すれば設定ファイルを読み込んでくれます。
<directory>でディレクトリを指定しておくと、その配下に存在するテストコード*Test.phpを全部見つけてきて、テストしてくれます。ディレクトリ構造が複雑でも再帰的に探します。include文にいちいち悩む必要もなく、テストコードからはシェバング行を取り除くことができ、きれいになりますね。
テスト時間が無視できない規模 → @groupを使う
テストが更に増えてくると実行時間がかかるようになってきます。特にDBが絡むテストなどは遅くなりがちです。時間がかかるテストは実行するのが億劫になってしまいますね。
こういう時、実行対象のテストを選べると便利です。開発している部分のテストだけ頻繁にチェックして、全体テストはコミット前だけ、というスタイルでも大抵は十分でしょう。
PHPUnitで対象のテストを絞り込む場合は、@groupアノテーションをテストにつけておくのが便利です。groupという名前ですが、概念的には「タグ」が近いと思います。
<?php
/**
* @group unit
* @group db
*/
class HogeTest extends PHPUnit_Framework_TestCase
{
// ...
}
こんな風にdocBlock内に@group グループ名の書式で書いておきます。グループ名に特に規約はありません。好きな名前をつけられます。
あとはphpunitの実行時オプションで、phpunit --group unitのように指定して、特定のグループのテストだけ実行したり、逆にphpunit --exclude-group dbとdbグループだけ実行対象から除外することができます。
例に書いたように、@groupは一つのテストに対していくつでも指定できるので、大カテゴリ中カテゴリとじゃんじゃん書けます。個人的には、「unit」「functional」「db」などをよく使っています。
@groupは、ディレクトリ構造に依存せず絞り込めるので便利です。phpunit.xmlのdirecotryによる指定を生かしたまま、書きやすいようにテストを配置したまま、絞り込みができるようになります。
その他細かいTips
賛否ありそうなところとか。
publicは省略
PHPはpublicメソッドのpublicを省略できます。別にdeprecatedエラーも起きないし、5.4でも許された真っ当な記法です。PHP界隈では省略せずにpublic function 〜と書くのが主流なようですが、テストにおいてアクセス修飾子が有効活用されるケースってあるでしょうか…?
横幅をとって読みにくくなるだけな気がするので、個人的にテストのときは省略して書くことにしています。
@testアノテーションを使う、日本語でテスト名をつける
テストメソッドは「test」で始まる名前をつける他、アノテーションでも指定できます。テスト名を日本語でつけたい場合、始まりが「test」だと不格好なので、アノテーションを使うようにしています。
// ...
/**
* @test
*/
function 1足す1は2() {
}
// ...
継承を使うときはabstractを活用する
PHPUnitではテストケースをクラスとして記述します。これはすなわち継承が使えるということを意味します。ここは、強調しすぎることはないってぐらいにPHPUnitの優位な点でしょう。似たようなsetup(), teardown()が発生するなら親クラスにまとめることでテストをDRYに書くことができます。
普通に親クラスを作ると、親クラス自体もテストケースとみなされて実行されてしまいます。これを防ぐには、親クラスをabstractで宣言しておくことです。abstractクラスは実体化できないので、テストケースとはみなされなくなります。
今のところ思いつくのはこんな感じでしょうか。PHPUnit_Storyを最近使っているので、こなれてきたらまた書くかも。



> テスト時間が無視できない規模 → @groupを使う
これは知りませんでしたが、軽いテストと重いテストを分けるときに特に有効そうですね。
参考にさせていただきます。