web-dev-qa-db-ja.com

プライベートメソッドの単体テストが悪い習慣と見なされるのはなぜですか?

環境:

現在、Pythonで小さなプロジェクトに取り組んでいます。私は通常、ドキュメント化されているが、主に高レベルの概念(クラスのユーザーが知って使用する必要のあるもの)とhidden(アンダースコアで始まる)複雑または低レベルの処理を担当するメソッド。

コードの信頼性を高め、その後の変更によって以前の動作が損なわれないようにするためには、テストが不可欠であることを知っています。

問題:

信頼できるベースで高レベルのパブリックメソッドを構築するために、私は通常、プライベートメソッドをテストします。コードの変更によってリグレッションが発生したかどうか、どこで発生したかを見つけるのは簡単です。これは、これらの内部テストがマイナーリビジョンで壊れる可能性があり、修正/交換する必要があることを意味します

しかし、私は、プライベートメソッドのユニットテストが、少なくとも異議のある概念であるか、またはより頻繁に悪い習慣と見なされていることも知っています。理由は:公共の行動のみをテストする必要がありますref。

質問:

以下のベストプラクティスに注意を払い、理解したいと思います。

  • プライベート/隠しメソッドでユニットテストを使用するのはなぜ悪いのですか(リスクは何ですか)?
  • パブリックメソッドが低レベルおよび/または複雑な処理を使用できる場合のベストプラクティスは何ですか?

精度:

  • ハウツーの質問ではありません。 Pythonにはプライバシーの真の概念がなく、隠されたメソッドは単にリストされていませんが、名前がわかっている場合に使用できます
  • 私はプログラミングのルールとパターンを教えたことがありません。最後のクラスは80年代からです...主に試行錯誤とインターネットでの参照(Stack Exchangeが何年もの間私のお気に入りです)によって言語を学びました
15
Serge Ballesta

いくつかの理由:

  1. 通常、クラスのプライベートメソッドをテストしたい場合、それはデザインの匂いです(icebergクラス、十分な再利用可能なパブリックコンポーネントなど)。ほとんどの場合、「大きな」問題が発生します。

  2. 公開インターフェースを介してそれらをテストできます(これは、クライアントがそれらを呼び出す/使用する方法であるため、テストする方法です)。誤った安心感を得ることができます。プライベートメソッドのすべてのテストに合格すると、青信号が表示されます。パブリックインターフェイスを介してプライベート関数でEdgeケースをテストする方がはるかに優れています。

  3. プライベートメソッドをテストすることにより、深刻なテストの重複(外観が非常に似ている/感じられるテスト)のリスクがあります。これは、要件が変更されると大きな影響を及ぼします。また、テストスイートが原因でリファクタリングが困難な状況に置かれる可能性もあります。これは、テストスイートが安全な再設計とリファクタリングを支援するために存在するため、究極の皮肉です!

まだプライベートパーツをテストしたい場合のヒント(YMMVが気になる場合は使用しないでください。ただし、以前はうまく機能していました):exactlyプライベート関数が機能していることを確認するために単体テストの単体テストを作成することは、(特に言語に慣れていない場合は)貴重であると考える場合があります。ただし、それらが機能することを確認したら、テストを削除し、public対面テストが確実であり、誰かがプライベートに重大な変更を加えた場合にキャッチされることを常に確認してください関数。

プライベートメソッドをテストするタイミング:この回答は(ある程度)普及しているため、「ベストプラクティス」は常に「ベストプラクティス」であることに言及する義務があります。それはあなたが独断的または盲目的にそれをすべきだという意味ではありません。プライベートメソッドをテストする必要があり、正当な理由がある場合(レガシーアプリケーションの特性テストを作成している場合など)は、次にプライベートメソッドをテストしてください。特定の状況alwaysは、一般的なルールやベストプラクティスよりも優先されます。うまくいかない可能性があるいくつかのことに注意してください(上記を参照)。

SOここでは繰り返さない)でこれについて詳しく説明する答えがあります: https://stackoverflow.com/questions/105007/should-i-test -private-methods-or-only-public-ones/47401015#47401015

17

単体テストの主な目的の1つがプログラムの内部をリファクタリングし、その機能を壊していないことを確認できることを考えると、単体テストが次のような細かいレベルで動作する場合、逆効果になります。プログラムコードを変更した場合は、テストを書き直す必要があります。

13
Pete

プライベートメソッドの単体テストを記述する単体テストを実装の詳細に結び付けます。

単体テストでは、クラスの外表面でクラスの動作をテストする必要があります(パブリックAPIです)。ユニットテストはクラスの内部について何も知る必要はありません。クラスの実装の詳細に対する単体テストを記述することは、リファクタリングの時期になるとあなたの手を縛ります。これらのテストは安定したAPIの一部ではないため、リファクタリングはほぼ確実にこれらのテストを中断させます。

とはいえ、なぜmightプライベートメソッドの単体テストを記述したいのですか?

単体テストと段階的な開発の間には自然な緊張があります。 REPL(read-eval-print loop))を使用するソフトウェア開発者は、クラスまたは関数を「拡張」しながら、機能の小さなビットをすばやく記述してテストすることの生産性を証明できます。単体テスト主導の環境でそれを行う唯一の良い方法は、プライベートメソッドの単体テストを記述することですが、そのためには多くの摩擦があります。単体テストの作成には時間がかかります。テストする実際のメソッドが必要です。テストフレームワークは、メソッドをプライベートにして外部APIを汚染しないようにする機能をサポートする必要があります。

C#や.NETなどの一部のエコシステムには、REPLに似た環境を作成する方法があります(Linqpadなどのツールでこれを実行します)が、プロジェクトにアクセスできないため、ユーティリティは制限されています。 Visual Studioのイミディエイトウィンドウは不便です。それでも完全なIntellisenseはまだありません。完全修飾名を使用する必要があり、使用するたびにビルドがトリガーされます。

10
Robert Harvey

私の経験から、内部クラス、メソッドを単体テストすることは、通常、テストされた関数、クラスを取り出さなければならないことを意味します。別の抽象化レベルを作成する。

これにより、単一責任原則の遵守が向上します。

6

カバレッジのテストで一般的な問題が明らかになるため、これは良い質問だと思います。ただし、理論的にはnotを単体テストできる必要があるためprivateメソッド。それが彼らがprivateである理由です。

「プライベートメソッドをテストしたい場合はどうすればよいですか?」で、答えは明白です。テストを可能にする方法でそれらを。さて、これは必ずしもメソッドを公開する必要があるという意味ではなく、それだけです。ほとんどの場合、より高度な抽象化を行う必要があります。別のライブラリまたはAPIに移動して、メインのAPIでその機能を公開せずに、そのライブラリでテストを実行できるようにします。

メソッドのアクセシビリティレベルが異なるのには理由があり、クラスが最終的にどのように使用されるかを常に考える必要があることに注意してください。