日々常々

ふつうのプログラマがあたりまえにしたいこと。

privateメソッドをテストしたい

と思うのは、とてもいいこと。

前置き

もし行いたいテストが外的振る舞いを示すものであれば(少なくともテストにより観測できる見通しがなければ「テストしたい」とは思わないだろうから、何かしら外から観測可能なものではある可能性は高い)、それがprivateに閉じていていいものではないと言う気づきのきっかけになる。

と言うのは教科書的回答だけど、外には見せたくないけれど複雑なロジックを包含していて、入念かつ局所的にテストしたいと思うこともある。 この動機はすごく自然。きっとそこはテストしなかったらバグってるし。テストしてもバグが見つからないと言うのもよくあるんだけど。 この手のがどうあるのがいいのかはチーム体制も含めたプロダクトによると思っている。

綺麗な考え方は、独立したコンポーネントとして関心ごとや複雑性を閉じ込め、テストしたいと思った内容にもっと高い格を与える。「格」なんて表現は他で使ったことないけど、privateよりもpublicのが格上、メソッドよりもクラスのが格上、みたいな感じです。伝わるよね? 少なくともメソッドと言う形での識別はできていて、そこをテストしたいと思うくらいは他よりも関心があるんだから。

privateメソッドをテストする方法はいくらでもある。プロダクトをテストのために少しなら歪めてもいいって考え方もある。レガシーコード改善ガイドだったかな。

(22:08追記) レガシーコード改善ガイドで合ってた。「10.1 隠れたメソッド」です。ここでは「private->publicに変更」で、私がよくやるのはパッケージプライベートへの変更。この可視性を緩めるのを「歪める」と表現しています。一番変更量少ないし、パッケージプライベートならpublicにするより影響範囲少ないし。「レガシーコード改善ガイド」の中ではpublicにすることへの抵抗感についても言及されています。気になる方はぜひお読みください。

Javaだとプロダクトを歪めずにテストしようとするとリフレクションが使えるけど、将来のリファクタリングを妨げるようになるのでイマイチおすすめはできない。でもやってもいい場面、やるべき場面もある。ほんとチーム体制も含めたプロダクト次第なんだ。言語によっては歪めずに可能だし。

ここまでが前置きで、正直privateメソッドをテストするかどうかなんてどうでもよかったりするんです。どうするべきかとかどう考えるべきかとかどうやったらできるかとかはそれはそれで楽しいんだけど、そこの話をするつもりはここではないんだ。あ、現場でならやります。

本題

表出した事象を叩き潰してはいけない。ここでは「privateメソッドをテストしたい」と感じたことが表出した事象。事象に直接アプローチする対象療法はこう言う文脈では害悪であり、私は人の感覚はだいたい正しいと思っている。でもなきゃコードスメル(嗅覚)なんて大真面目で言えない。

にもかかわらず、経験の多寡に関わらず「privateメソッドをテストしてはいけない」と言う言葉をまにうけて、「privateメソッドのテストをしたいと思った自分が間違っている」と考えてしまったりする人も結構いる。とても勿体ない。

無理に抑えつけず、テストしたくなったんだから、テストしよう。……ってのは私が「不安をテストに」に軸足を置いて強振できるから言えることだけど、そうでなかったとしても「テストしたい」と思った感覚をもう少し信じてみて欲しい。

信じて向き合って考えたら、本当に要らないかもしれない。でも要らないと言うには何かしらの裏付けが必要になる。先に挙げたように設計で「privateメソッドのテスト」ではなくせるかもしれないし、テスト技法かもしれないし、他の何かかもしれない。それが技術であれば身につけられるから、考えることは無駄にはならない。どうにもならなかったら無理矢理テストしたらいいんじゃないかなとも思う。それがあまりよくなかったら、そのフィードバックを受けることになるはず。(手が離れてしまってフィードバックを受けれないかもしれないけど、それは仕方ない。)

「privateメソッドをテストしてはいけない」って言葉は「privateメソッド だから テストしてはいけない」という呪いに容易に変わってしまう。そうじゃないって言いたい。「privateメソッドをテストしたい」と思った感覚は、その瞬間その場その人にとって、絶対に正しい。「そのprivateメソッドをそのままテストしなきゃいけない」かどうかは別の話。

プログラマなんてものを生業にしててなんだけど、もっと感覚を信じてもいいんじゃないかなって思うんです。

蛇足

privateメソッドのテストについてこのブログに何か書いてないかなーと検索してみたけど、9年前に書いたブログくらい。

irof.hateblo.jp

ここでも 開発の初期段階はともかく最終的にはpublicな属性を相手にしたテストで賄ってしまって削除しちゃったほうがいいと思います。 とか書いてる。まーそうだよねって。結局のところprivateメソッドをprivateなままテストするのは(少なくとJavaにおいては)リファクタリングの妨げになるので、よほどの理由があるときにそのマイナスをプロダクトとして許容して行うものだと思う。

まっとうな話

ここまで思ったことをだーっと「私はこう考えてる」ってのを書こうと思って書きました。なんとなく思い立ったんで。

まっとうな考え方とかを知りたい方のためにリンク置いておきます。

t-wada.hatenablog.jp