JUnitでみるデザインパターン活用術 (2)

testcase2
testcase
今回は、Testインターフェイスとその派生クラスについて見てみることにする。

クラス図で示したとおり、Testインターフェイスを実装しているクラスは2つある。
TestCaseクラスとTestSuiteクラスだ。
TestSuiteクラスはTestインターフェイスインスタンスVector配列で持っている(オレンジの枠で囲ってある部分)
これはつまり、「Compositeパターン」そのものだ。
Compositeパターンとは、容器と中身を同一視するパターンで、入れ子構造を表す時に非常に有効だ。
赤で囲ったaddtestメソッドでTestCaseクラスもしくはTestSuiteクラスをこのクラスに追加できるようになっている。
そして、runメソッドですべてテストクラスを舐め回すようにテストが動くってわけだ。(緑の下線)

つまり、2番目の画像のような構造にできるというわけだ。
ディレクトリ構造と同じだ。

さて、Compositeパターンの説明はこの程度にして、
JUnitでどのように使われているかについて説明していこう。

JUnitでは通常テストできるクラスは1つだけだ
java junit.textui.TestRunner テストクラス名
とすることで指定したテストクラスのテストを行う。
しかし、テスト駆動を行う場合、実クラスとテストクラスは対応するように作成するため、実クラス≒テストクラスとなる。

1つ1つをTestRunnerに渡していたのでは効率が悪すぎる。
そこで2つ以上のテストを透過的に実行する手段がある。
それがTestSuiteを使ったやり方だ。
TestSuite suite= new TestSuite("All JUnit Tests");
suite.addTest(new TestSuite(テストクラス名1));
suite.addTest(new TestSuite(テストクラス名2));
としてsuiteをTestRunnerに渡してやることにより、これを実現する。

ここまでは、今まで使ってきた中で知っていたのだが、
今回、新たな発見があった。

TestCaseクラスを見てもらえば分かるのだが、TestCaseクラスにはpublicなtest*をすべて走査し実行するというコードがない。
あるのは以下のようなコードだ。=>TestCase#runBare()
try {
  setUp();
  runTest();
} finally {
  tearDown();
}
かなり省略しているが、setUp→runTest→tearDownで処理が完結している。
ご存知の通り、setUp〜tearDownは各テストメソッド毎に行われるものなので、runTestでは1つのテストしか行われていないのは明確だ。

どういうことかと追ってみると、
その答えはTestSuiteにあった。
TestSuiteでは、addTestメソッドで渡されたTestCaseをそのまま格納するのではなく、
メソッド単位で格納していた。
つまり、こういうことだ。
SampleTestに以下の3つテストがあったとしよう。
SampleTest#test1()
SampleTest#test2()
SampleTest#test3()

TestSuiteクラスは渡されたtestの中身を走査し、
上の3つに分けて格納するようになっている。

1つ目の画像のTestCaseクラスにはfNameというフィールドがあるが、そこに実行するメソッド名が格納されている。

このようにTestCaseクラスは1つのテストを担当することで、
繰り返し実行やその管理はすべてTestSuiteクラスで一元管理できるってわけだ。
すばらしくスマートに書かれていると感心してしまった。

さて、余談だが、
最初の画像で青紫の下線を引いたメソッドが2つある。
isPublicTestMethodとisTestMethodだ。
これは読んで字のごとくのメソッドなのだが、
呼び出し元を見るとすばらしさが分かる。=>TestSuite#addTestMethod()
if (! isPublicTestMethod(m)) {
  if (isTestMethod(m))
    addTest(warning("Test method isn't public: "+m.getName()));
  return;
}
これはpublicなテストメソッドでなく、test*という規則には適合しているメソッドの場合、warningを出す処理だ。
やっていることはリフレクションを使う複雑なことなのだが、ぱっと見て分かる。
「真のプログラマーは人間が分かりやすいコードを書く」
まさにこれの典型だ。
比較文は暗号的になりやすい典型なので、
暗号的になってきたと思ったら、比較文の部分をメソッド抽出し、
分かりやすい名前をつけることでコードが恐ろしく見やすくなる場合がある。