Index: [Article Count Order] [Thread]

Date:  Sat, 30 Sep 2000 01:47:47 +0900
From:  firo@....jp
Subject:  [XP-jp:00986] Re: Why do I test private methods?
To:  extremeprogramming-jp@....jp (extremeprogramming-jp ML)
Message-Id:  <39D4CC00.1202BF85@....jp>
References:  <000101c02a22$cf8c31a0$010400c8@Ra20>
Posted:  Sat, 30 Sep 2000 02:06:10 +0900
X-Mail-Count: 00986

矢崎です。

Kenichiro Ootaさん wrote:

>
> > 内容は、
> > private methodはテストすべきかどうか?というような内容
> > です(投稿全てに目を通していないので、今は別の方向に
> > 流れていっているものもあるかもしれません)。
> >
> > すべき、すべきでない、の意見にわかれています。本家の
> > ほうでも、いろいろな考えがある、ということですね。
> >
> > R.Jefはprivateメソッドをテストするのはよい、という意見の
> > ようです。
>
>  従来のテストの考え方ですと、カバレッジとantidecompositionの法則から
> テストすべきとなりますが、テストすべきでないという意見は面白そうです。
> コードはテストできなければならないというXPの考え方からはテストすべきと
> なるような気がしますがどうなのでしょう。
>
>  privateにアクセスしようとすると何らかに形でコードを破壊したり、テス
> トケースが複雑になりすぎたりするからいかんということでしょうか。
>
> 早稲田大学大学院理工学研究科情報科学専攻M2 太田健一郎
> e-mail Address oota@....jp
>                oota@....jp

これは、あくまでも私の個人的意見ですが、
XPのテストを先に書いてからコードを書くという
原則からすれば、テストは仕様に近く(これは別の
ご投稿でもご指摘ありましたが)、であるがゆえに、
公開されたメソッドしかテストをしない、というのが
もっともかな、とずっと思ってきています。つまり、
公開されたメソッド、つまりパブリック・メソッドは
外部への契約であり、それがテストを先に書くと
いう行為でテストの中にその契約内容が具体的
に述べられるというわけです。

テストを先に書くということからすれば、テストを
書いているときには、その実現方法は、いったん
は棚上げしなければならないのではないでしょうか?
ですから、プライベートメソッドや属性というものは
テストを書くときには、決まっていないわけですし、
おぼろげながら、こういうのがありそうだ、と感じて
いても、コードを書きながら、あるいはいったん
書いたコードをリファクタリングする中で、消えてしま
うかもしれません。

また、プライベートメソッドについていえば、これは
それを使うコンテクストがそのクラスの他のメソッド
のふるまいに限定されています。例えば、あるクラス
に次の2つだけのメソッドがあったとします。

private int warizan(int a, int b){
    if (b == 0) return 100;
    return a/b;
}

public int koukaiwarizan(int a, int b){
    if (b ==0) throw new RuntimeException( );
    return warizan(a, b);
}

この場合、warizanのテストを行わなければならな
いかを考えたことがあります。

bのシグニチャからすれば、bは0を受け取ることもでき
ますが、しかし、これはプライベートですし、使われる
のは、koukaiwarizanからしか使われないわけです。
そして、koukaiwarizanの中では、絶対にwarizanの
bに0を与えないようにしている。

もし、warizanがパブリックとして、そして普通通りの
わりざんの機能を予定されているとしたならば、bに
0がわたるケースもテストしなければなりません。
koukaiwarizanの場合も同じで、そしてこの場合は正しく
例外がかえってくる、となります。

一方warizanの場合、bが0だと答えが100で、これは
変です。しかし、今回はwarizanはprivateですし、
それを呼ぶメソッド(koukaiwarizan)の中で、決して
warizanのbに0がわたらないようになっている。だから
このwarizanメソッドは、今のロジックでprivateである
限りは、変なことはしないわけです。そして、そのこ
とは、warizanのテストを通してというよりは、koukaiwarizan
のaとbの全てのケース(aとbの全てのケースをテストす
ることは、実際は不可能ですBy G.Jマイヤー)をテスト
することで、warizanメソッドの、それが帰属している
クラスの中の限定されたコンテクストの中での、
正さがテストされる、というわけです。逆に、warizanに
ついて、これが公開される可能性も考えて、bに0を
与えてテストすることは、過剰テストであるとの考え
も有り得るかと思います。

#日本語がめちゃくちゃです。勘弁してください。

とまあ、とりとめもないですが、XPでのテストの仕様性
あるいは契約文書的な面、および、プライベートメソッド
は使用コンテクストが限定されていて、その限定された
コンテクストの中での正しさは、そのクラスのパブリック
メソッドの網羅的なテストで暗黙的にテストできる、という
点から、プライベートのテストは不要だと、結論をだしました。
#プライベートが別のプライベートを呼んでいるとしても
、最終的にはすべての入り口はパブリックですよね。


と、ここまでは、表向きの話。


私の本音は、ちょっとちがいます。プライベートメソッドも、
必要ならテストをすべき、と思います。それが安心料で
あっても、です。そして、これは、まったく実務的な観点
からの主張です。

XPの命の1つはスピードだと思っています。そして、そこ
にプライベートメソッドや変数があって、そしてそれをテスト
したい。テストをしたほうが、先にすぐ進める、と思ったとき
には、マシンの前で、それを別の手段でテストしようと、あ
れこれ迷うのではなくて、もう、それを直接テストしたほう
がよい、と思うのです。

上記のwarizanの例でいえば、最初から、

private int warizan(int a, int b){
    if (b == 0) throw new RuntimeException( );
    return a/b;
}

にしておけばいいと思いますし、そのつもりでテストすれば
いいと思うのです。ある事情で、どうしてもbに0が
わたることを考慮したくないとしたら、テストを書くときに
bに0がわたるテストケースを書かなければいいだけの
話だと思います。

また、最初にテストを書くときには、privateメソッドは、見えて
いない、というのは本当だと思います。ですから、最初のテスト
では、プライベートのテストを書くのはできないでしょう。

しかしXPの場合、テスト、コード、テスト、コードと帽子を何回も
かぶりなおしながらやるので、何回めかのテストを書くときに、
そのときプライベートメソッドをテストしたい、と思ったら、それを
書けばいいのではないでしょうか?

XPのJUnitの使い方は、ブラックボックスが主眼であり、
ホワイトボックスやカバレジテストは、従だと思います。
だから、全てのパブリックテストをテストすべき、だとは
思いますが、全てのプライベートをテストすべき、とは
思いません。また、ブラックボックスは徹底的にやるべ
きだと思います。私はパブリックなgetメソッドや、setメ
ソッドもやるべきだと思っています。(単純なメソッドは
やらない、というのが公式見解のようですが)対して、
ホワイトボックスやカバレジをXPの中で徹底的に行う
のには疑問符です。(アプリの種類によっては必要で
すが)。

しかし、全てをブラックボックスというように固執する
のもナンセンスなような気がします。中心はブラック
ボックス、パブリックメソッドであっても、それを補完す
るプライベート系のテストも、必要ならどんどんやれば
よい、と考えています。プライベートメソッドのテストを
することについての、害があるとは思いませんし、
ブラックボックス的にいえば、少々余分であっても、
テストは余分にやる分には、なんら問題ないと考えて
います。

太田さんは、ソフトウエア全般に関してのご研究として、
ホワイトボックステストをおろそかにしてはいけない、
というご意見かもしれません(これは私の勝手な想像
です。ちがっていたらごめんなさい)。もし、そうだと
して、上記に述べてきたような私の考えは、少々甘い
かもしれません。

太田さんのテスト観から、XPのテストについて、いろい
ろご批評していただくのも非常に興味を覚えます。もし、
お時間ありましたら、いずれ、そのあたりのことを教え
ていただけたら、うれしく思います。

#いやー長文になってしまいました。ごめんなさい。

--
矢崎 博英 <firo@....jp>