早稲田大学の太田です。テスト関連なので出てきました(XPについてはまだ
まだ勉強中です)。
私はテストのためのパターンという立場から発言させて頂きます。
オブジェクト指向のカプセル化により逆にテストがしにくくなっているとい
うのは周知の事実ですよね。オブジェクト指向の場合カプセル化を何らかの形
で破壊しない限り内部の状態をすべてみることは不可能となります。その方法
が本来機能としては必要のないメソッドを書き加えたり、フレンドを許した
り、protected属性にしたりというものであったりします。
これらの方法はBinderの「Testing Object-Oriented Systems」によるとそ
れぞれパターンとして述べられているわけですが、それぞれ
・Controllability (管理のしやすさ、任意の状態に変更したり出来る)
・Observality (結果の見やすさ、結果をどのような形で観察したいのか)
・Reuse (テスト自体の再利用のしやすさ)
の三つフォースを考慮して選択すべきだとしています。パターンの観点から
言えばどれが一番良いというのはなくて、どのフォースを最も重視しているか
によって選択するということになります。既に大村さんが仰られているように
クラスの内部を正しく検証するのが要求として存在するなら、テストのためだ
けのメソッドが必要であっても構わない、否必要不可欠であるとも言えます。
ただ、それを対象のクラス本体に含めるか、別クラスにするかはまた別の問題
であると思います。
一応、
http://www.rbsc.com/pages/HarnessPatternList.htm
からテストとのためのメソッドというのに関係しそうなパターンを述べておき
ますと、
・Percolation
大村さんの仰っているクラス自身に事前、事後、不変条件を組み込むパター
ンです。アサーションのメソッドは独立しています。Eiffelでは言語自体に組
み込まれていますね。Javaですとtry and finallyイディオム、final変数のイ
ディオムによりオンオフが出来ます。
パターンですのでメリットとデメリットが書いてありますが、メリットは、
可読性の向上、サブクラスのテスト性向上、デメリットはメンテナンスの増
加、実行コードの増加、LSPとdesign-by-contractの理解などです。
・Server Proxy
GoFのProxyパターンを使用してテスト専用のメソッドをProxyに実装するパ
ターンです。本体にはテスト専用のメソッドを付け加えたくない場合に有効で
す。対象クラスはControllabilityとObservalityを備えていない場合が多いの
で実行中のログを取ったり標準出力ではないほかの出力に出力したりというの
はこのServer Proxyに任せるわけです。Strategyパターンと組みわせてログの
出力を複数切り替えられると面白いですね。
ただ、実装の際には、Server Proxyはテスト対象のクラスのサブクラスにな
るので、正確なテストを行うにはサブクラスにメンバを公開する必要が出てく
るという問題が出てきます。このためにメンバをprotectedにしたり、friend
を導入したりする必要があるかもしれません。
・Built-in Self Test
これもクラス自身に自己テストを組み込むパターンなのですが、内部クラス
を使用してテスト対象クラス自身には余分なメソッドを付け加えないのが特徴
です。内部クラスでしたらテスト対象クラスのプライベートメンバにもアクセ
スできますね。JUnitを使用した実装例が述べられています。ただ、テスト
ケース自体が内部クラスとなっているので可読性は若干落ちるかもしれませ
ん。結果の項においてメリットとデメリットについて詳しく述べられていま
す。
・Fresh Objects
新規開発で主に用いられるパターンで、すべてのクラスは自己テストが行う
インタフェース、若しくは抽象クラスから継承するというパターンです。新規
開発の時にはかなり効果がありますが、既存のシステムに組み込むのは難しい
とのことです。実装例としてはSmalltalkのTOBACというシステムが有名だとい
うことです。
中にはXPのプラクティスに反するものがあるかもしれませんが、こんなもの
もあるよということで。
最後に、話はそれますが、XPのクラスを書く前にそれをテストするコードを
書くというの言うのは非常に良いことだと思いますが、メリットデメリットを
持っていると思います。
メリットしては、
・実装によらない要求を正しく反映したテストが書ける
・テストを書くことによって要求が明確になっているかが分かる
デメリットしては
・正しくテストと作ったとしても、実装したクラスに対してすべての網羅が出
来るとは限らない
・悪意を持って実装を行うと書いたテストのみが通る実装になる
・メソッドの正しさを保証するにはテストが少なければ少ないほど良いという
矛盾[Myer79]が発生する
となります。逆にクラスを書いてからそのテストを書くという場合は、
メリット
・網羅基準が明確になる
・やろうと思えば完全な網羅が出来る
・例外などにも強い
デメリット
・機能に注目せず、網羅すれば良いというテストが出来る
・下手をするとテストが省略される
というのがあります。どちらにしてもテストコードのメンテナンスの手間は
残ります。「Jtest」などの完全自動テストツールの出現と、上記を考慮する
と、すべてのテストを事前に書くというのに固執するのではなく、正常ケース
については事前にテストを書き、異常ケースに関しては完全自動ツールにまか
せてしまうというのも1つの手かなとも考えます。たとえ、ペアプログラミン
グをしても人間である以上異常ケースの想定には限界があるのでツールに任せ
てしまう方がテストケースの見通しもよくなるように思えるのです。
では。
早稲田大学大学院理工学研究科情報科学専攻M2 太田健一郎
e-mail Address oota@....jp
oota@....jp