第2章 PHPUnit の目標

いまのところ、組み込みの array および count() 関数のテストしかありません。 PHP が提供する数多くの array_*() 関数をテストしようとすると、それらそれぞれについてテストを記述する必要があります。 それらのすべてのテストについて基盤部分を最初から書いていくこともできますが、 共通部分は一度だけ記述するようにし、 個々のテストではテスト固有の部分のみを記述していくほうがずっとよい方法です。 PHPUnit は、そのような基盤部分を提供します。

PHPUnit のようなフレームワークには、解決しなければならない制約があります。 その中のいくつかはお互いに相反するものです。 テストは、以下の条件を同時に満たす必要があります。

記述方法を習得しやすいこと。

テストの書き方を身に着けるのが難しければ、 開発者はそんなものを覚えようとしないでしょう。

記述しやすいこと。

テストが書きにくければ、開発者はそんなものを書こうとしないでしょう。

読みやすいこと。

テストコードには、外部からの要素を含めるべきではありません。 そうするとテストコードが周りのノイズに埋もれてしまいます。

実行しやすいこと。

ボタン一発でテストが実行でき、 その結果は明白な形式で表示されなければなりません。

すばやく実行できること。

一日に何百何千というテストを実行できるよう、 テストはすばやく実行できなければなりません。

独立していること。

テストは、お互い他のテストに影響を及ぼしてはいけません。 テストの実行順序を変えることでテストの結果が変わってしまってはいけません。

自由に組み合わせられること。

テストの数や組み合わせを自由に選択できなければなりません。 テストが独立している以上、これは当然のことです。

これらの制約の中には、相反する項目が 2 点あります。

習得のしやすさか書きやすさか。

一般に、テストにはプログラミング言語の全機能を必要としません。 多くのテストツールは、テストを記述するため必要最小限の機能のみを組み込んだ 独自のスクリプト言語を提供しています。その結果、テストは読みやすく、 また書きやすいものになります。 なぜならテストの内容から気をそらせるノイズがないためです。しかし、 またひとつ新たなプログラミング言語やプログラミングツールの使い方を覚える必要があり、 不便です。

独立か実行速度か。

ひとつのテストが他のテストの結果に何の影響もおよぼさないようにするには、 各テストの実行前に毎回テスト用の環境を構築し、 終了後には毎回それを元の状態に戻す必要があります。しかし、環境を構築する (例: データベースに接続し、特定の状態を表すデータを投入する) には長い時間がかかります。

PHPUnit は、テスト言語として PHP を使用することで これらの衝突を回避しようとしています。小規模で単純なテストを行う際には、 PHP の機能は行き過ぎた面もあるかもしれません。しかし、PHP を使用することで、 これまでの開発経験や開発ツールを武器として利用できます。 あまり気乗りしないテスターを納得させるため、 テストを最初に書き始める際の負担をできるだけ下げることが重要だと考えています。

PHPUnit では、実行速度よりもテストの独立性を重視しています。 独立したテストに価値があるのは、そのほうがより高品質のフィードバックが得られるからです。 一連のテストの最初のほうで失敗したことでその後のすべてのテストが失敗してしまい、 大量の失敗報告を受け取るようなことがなくなります。 このオリエンテーションでは独立したテストを目指し、 シンプルなオブジェクトを数多く作るという設計を心がけます。 各オブジェクトは独立してすばやくテストできます。結果としてよりよい設計 に加えてより高速なテストが可能となります。

PHPUnit ではほとんどのテストが成功することを想定しており、 成功したテストの詳細について報告することはあまり価値がないと考えています。 テストが失敗した場合には、そのことをしっかり報告しなければなりません。 大半のテストは成功すべきであり、 それらについては実行したテストの数以外に特にコメントすべき情報はありません。 これは、PHPUnit のコアではなく報告用のクラス群に組み込まれている機能です。 テストの結果が表示される際には実行したテストの数が表示されますが、 詳細が表示されるのは失敗したテストについてだけです。

テストはきめ細やかに行うこと、つまりひとつのテストではひとつのオブジェクトの ひとつの機能についてをテストするようにすることが期待されています。 そのため、最初のテストは失敗し、テストの実行は終了し、 PHPUnit は失敗を報告します。多くの小さなテストを実行させることは一種の芸術です。 きめ細やかなテストにより、システム全体の設計がよりよいものとなります。

PHPUnit でオブジェクトをテストする際には、 その公開インターフェースについてのみテストを行います。 公開されている振る舞いにのみ基づいてテストを行うことで、 設計上の困難な問題により早い段階で対応できるようになり、 設計ミスがシステムの大部分に影響を及ぼすことを避けられます。

このページの改善案をGitHubで提案してください!