1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「privateだからテストしない」は思考停止

Posted at

「privateメソッドにはテストを書くな」

有名な原則です。私も基本的には賛成です。

しかし、原則に縛られて、本当に必要なテストを諦めていませんか?

publicとprivateの違い

publicメソッドは、概念への窓口——外部に公開された安定したインターフェースです。当然、それに対するテストも安定します。

一方で、privateメソッドは内部実装の詳細です。リファクタリングで増減しますし、publicメソッドの変更にも影響を受ける不安定なものです。それに対するテストは当然、不安定なものとなります。

不安定なテストが招く実害

不安定なメソッドに対するテストは、メンテナンスコストが高くつきます。

リファクタリングしたいのに、テストの書き換えコストが重すぎて断念する。そんな状況は避けるべきです。

だから「privateメソッドはテストしない」が原則になるのです。

共用ロジックというジレンマ

複数のpublicメソッドから呼ばれる共用ロジック。public経由でテストすれば、同じ検証を複数箇所で繰り返すことになりかねません。

共用ロジックを直接テストすれば、一箇所で済みます。

しかし、先述の通り不安定なテストのコストは高くつきます。privateメソッドを直接テストするなら、本当にそれが必要か吟味しなければなりません。

「別クラスに切り出せ」への疑問

「テストしたいなら、別クラスのpublicメソッドにしろ」これはよく耳にする解決法です。

もちろん、設計上自然な分割であれば切り出すべきです。単一責任原則に沿った分割は歓迎されます。

ところが、テストを書くためだけにクラスを分割するのは話が違います。凝集度の高いクラスが分割される。privateだったロジックが、別クラスとはいえpublicになる。どちらも避けるべきことです。

テストの都合でプロダクトコードを歪めることは、本意ではないはずです。

privateなインターフェース

privateメソッドはインターフェースではない——普通はそう考えます。

しかし「独立してテストを書きたい」と強く思うprivateメソッドは、複数のpublicメソッドから共有される「内部概念」への窓口である可能性があります。

その内部概念が重要であれば、publicメソッドと同じ慎重さで設計する価値があります。その結果、そのprivateメソッドは「安定した内部インターフェース」になります。それに対するテストもまた、安定するでしょう。

これは「別クラスに切り出せ」と本質的には同じことをしています。整理する、ただし分割と公開はしない——それだけの違いです。

原則と例外

原則を守るのは大事です。でも、「なぜ」を理解せずに従うのは思考停止です。公開範囲だけを理由に、真っ当な判断を諦める必要はありません。

もっとも、これが当てはまるケースは多くありません。ほとんどのprivateメソッドは、ただの実装詳細、もしくは独立したテストを書く必要がない内部概念です。

例外が許されるのは、以下の条件をすべて満たす場合に限ります。

  • 独立したテストを書きたいと強く思う
  • クラスにすべきではない内部概念である
  • コードを整理して安定したインターフェースにできた

一つでも欠ければ、そのテストは書くべきではありません。

また、これらの判断には経験が要ります。見極められる人がいて、コードレビューが機能している——その環境がなければ、全面禁止が正解です。

「privateだから」で止まるな。その先を考えろ。

原文: https://sijiaoh.com/posts/private-method-test-rethink/

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?