バグ解消法、お役立ち情報など

プライベートメソッドをテストするのはアンチパターンです

PHPUnit logo

本稿の内容は、書籍「単体テストの考え方/使い方」の11章を切り取ったものです。

単体テストの考え方/使い方 | マイナビブックス

結論

プライベートメソッドをテストするのはアンチパターンです!

テストの対象は、パブリックメソッドのみにしましょう。

詳細

なぜプライベートメソッドをテストしてはいけないのでしょうか?

それは、テストが壊れやすくなってしまうためです。

プライベートメソッドをテストすると、テストが実装の詳細と結びついてしまい、「退行に対する保護」を失うことになります。

(退行に対する保護とは、新たな機能を追加することで既存の機能に不具合が発生することです)

テストすべきは、外部から見た振る舞い(= ユニットテスト)なのです。

もしあなたが「プライベートメソッドがあまりに複雑で、動作を検証したいからテストを書きたい」と思ったら、それはプライベートメソッドの処理を適切に分けたほうがよいでしょう。

別のメソッドやクラスに処理を分けることを検討しましょう!

ただし、本書の中では1つだけプライベートメソッドをテストすべきシチュエーションについて触れられています。

それは、プライベートなプロパティがドメインにおける重要な振る舞いを表している場合です。

こうしたケースはごくごく稀なので、よほどのことがない限りは「プライベートメソッドはテストしない」と考えてよいでしょう。

他のアンチパターン

ついでに、本書で紹介されている他のアンチパターンにも軽く触れておきます。

プライベートな状態の公開

テストを行うために、プライベートな状態を公開する、というのはアンチパターンです。

プライベートにできるのであれば、プライベートにしましょう。

カプセル化を意識することで、コードの品質を上げることができます。

テストへのドメイン知識の漏洩

テストにロジックが入ってしまうと、アンチパターンとなります。

例えば以下のコードです。

テスト対象メソッド
public function add(int $value_1, int $value_2): int { return $value_1 + $value_2; }
アンチパターンのテスト
public function test_adding_two_numbers(): void { $value_1 = 1; $value_2 = 2; $expected = $value_1 + $value_2; // ← ドメイン知識の漏洩 $actual = $this->add($value_1, $value_2); $this->assertSame($expected, $actual); }

このようなテストは、実装の詳細と結びついていると考えることができ、避けるべきものです。

解決策として、テストには固定値を使うようにしましょう。

OKのテスト
public function test_adding_two_numbers(): void { $value_1 = 1; $value_2 = 2; $actual = $this->add($value_1, $value_2); $this->assertSame(3, $actual); // 固定値を使用する }

おわりに

ここまでの内容をまとめると以下のとおりです。

  • プライベートメソッドはテストしない
  • テストのためにメソッドを公開しない
  • テストにドメイン知識を漏洩させない

以上です!

では、よいテストライフを!

バグ解消法、お役立ち情報など