先週privateメソッドのテストがしたい話を書いたけど、2点補足。
まず、テストを実際にやる方法について。
自分はprivate相当のメンバーの可視性は、なるべくpackage privateにする。settter/getterがあったり、テストに直接は関係無さそうだったらprivateにする。
(つまり、「privateにする=直接はテストしない」という意味でprivateを使っていることになる^^;)
コーディング規約とかでどうしてもprivateのままにしてテストをしないといけないなら、リフレクションを使うしかない。
けど、リフレクションはちょっと手間がかかるし、メソッド名やフィールド名を文字列で指定すると、不一致だった場合にコンパイルエラーになってくれないので、あまり好きではない。
privateメソッドをクラスにするという方法もあり、メソッド分割だけでなくクラスに分割した方がいい場合もあるという事については大いに賛成。
ただ、その場合のクラスの可視性については、自分はprivateにしたいと思う。
前回の例(ID0001Logicクラス)で言えば、 値を算出するのはLogicクラス自身の責務なので、機能を分割して下請けクラスを作るにしても、その下請けクラスはLogicクラスからだけ参照できるようにするのが筋だと思う。
この下請けクラスがpublicやpackage privateでいい(Logicクラス以外からも呼び出せても構わない)のであれば、そもそも当初のLogicクラスのcalculateメソッド自身もpublicやpackage privateでいい(Logicクラスの外から呼び出せても構わない)はず。
Javaの場合は、クラスの可視性をprivateにするにはインナークラス(厳密にはnested classらしい)にする必要がある。
で、privateなインナークラスは、やっぱりテストクラスからはアクセスできないという問題があり、「クラスにする」というだけでは解決にならない。
(解決策として言われる「クラスにする」というのが「publicクラスにする」という意味だったら、やっぱりもやもやする…)
(とは言え、下請けクラスは自分しか使わない(はずの)ユーティリティーのようなものだとも思えるので、それならpublicでも構わないのか…?)
もうひとつは、メソッド分割(クラス分割)を何の為に行うのか?ということ。
分割すると責務の範囲とかソースの見た目が分かりやすくなる・構造を理解しやすくなるというメリットはあるけど、自分はテストのしやすさの為に分割している気がしてきた。
例えば、
public void execute() { if(isTarget()) process1(); else process2(); } private boolean isTarget() { return 複雑な判定; } private void process1() { 複雑な処理 } private void process2() { 複雑な処理 }
このようなソースの場合、executeの中に全部を書くことが出来るけど、isTarget・process1・process2を別々にテストする方が効率がいいと思う。
executeの中に全部書いていたら、isTargetの中に相当する部分をテストするのにprocess1やprocess2も絡んできてしまう。
結論として、可視性とテスト実施有無は、本来は関係ないと思う。
Javaがprivateメンバーに外部からアクセスできないから問題になるのであって、「privateのテストがしたいというのは間違い」はやっぱり間違っていると思う。
テストクラスだけはフルアクセス可能にするような仕組みがあるといいんだけどなぁ。
C++のfriendみたいなものが欲しかった^^;
(下手にそういう構文を用意してしまうと、意図を理解していない人がテストコードだけでなくプロダクトコードに対しても使ってしまいそうで、微妙だけど(苦笑))