私は今TDDを学んでいます。私の理解では、プライベートメソッドはテスト不可能であり、心配する必要はありません。パブリックAPIがオブジェクトの整合性を検証するための十分な情報を提供するからです。
私はOOP=をしばらく理解しました。プライベートメソッドはオブジェクトをよりカプセル化するため、変更やエラーに対してより耐性があることを理解しています。したがって、これらはデフォルトで使用されるべきメソッドとクライアントへの問題は公開されるべきです。
ええと、私はプライベートメソッドのみを持ち、イベントをリッスンすることによって他のオブジェクトと対話するオブジェクトを作成することが可能です。これは非常にカプセル化されますが、完全にテストできません。
また、テストのためにメソッドを追加することは悪い習慣と見なされています。
これは、TDDがカプセル化と対立していることを意味しますか?適切なバランスとは何ですか?私は自分のメソッドのほとんどまたはすべてを今公開する傾向があります...
プライベートメソッドはテストできないというのが私の理解です
これは開発環境によって異なります。以下を参照してください。
[プライベートメソッド]は心配する必要はありません。パブリックAPIがオブジェクトの整合性を検証するための十分な情報を提供するためです。
そうです、TDDはインターフェースのテストに焦点を合わせています。
プライベートメソッドは、リファクタリングサイクル中に変更される可能性のある実装の詳細です。インターフェースやblack-box動作を変更せずにリファクタリングできるはずです。実際、それはTDDの利点の一部であり、クラスの内部の変更がそのクラスのユーザーに影響を与えないという確信を簡単に生成できることです。
ええと、私はプライベートメソッドのみを持ち、イベントをリッスンすることによって他のオブジェクトと対話するオブジェクトを作成することが可能です。これは非常にカプセル化されますが、完全にテストできません。
クラスにpublicメソッドがない場合でも、イベントハンドラーはpublic interfaceであり、それに対してthatテストできるパブリックインターフェイス。
イベントはインターフェースなので、そのオブジェクトをテストするために生成する必要があるのはイベントです。
mock objects をテストシステムのglueとして使用することを検討してください。イベントを生成し、結果として生じる状態の変化(別のレシーバーモックオブジェクトによって可能)を取得する単純なモックオブジェクトを作成することが可能でなければなりません。
また、テストのためにメソッドを追加することは悪い習慣と見なされます。
絶対に、内部状態を公開することに非常に注意する必要があります。
これは、TDDがカプセル化と対立していることを意味しますか?適切なバランスとは何ですか?
絶対違う。
TDDは、おそらくそれらを簡略化する以外にクラスの実装を変更すべきではありません(以前のポイントから [〜#〜] yagni [〜#〜] を適用することによって)。
TDDを使用する場合のベストプラクティスは、TDDを使用しない場合のベストプラクティスと同じです。開発中にインターフェイスを使用しているため、理由がすぐにわかります。
私は今、自分のメソッドのほとんどまたはすべてを公開する傾向があります...
これはむしろ、赤ちゃんを風呂の水で捨てることです。
TDDの方法で開発できるように、すべてのメソッドをパブリックにするneedするべきではありません。以下の私のメモを参照して、プライベートメソッドが本当にテストできないかどうかを確認してください。
言語/環境に応じて、クラスのプライベート動作を絶対にユニットテストする必要がある場合、次の3つのオプションがあります。
明らかに、3番目のオプションが最善です。
テスト対象の本番コードと同じクラス/ソースファイルにテストケースを保存するのが最も簡単なオプションです。しかし、プリプロセッサディレクティブやアノテーションが多くなければ、テストコードが本番用コードを不必要に肥大化し、コードの構成方法によっては、誤って内部実装をそのコードのユーザーに公開してしまう可能性があります。
これは非常に貧弱な習慣であることを示唆しているように、カプセル化を破壊し、内部実装をコードのユーザーに公開します。
Eclipseの世界では、3。は fragments を使用して実現できます。 C#の世界では、 部分クラス を使用できます。他の言語/環境も同様の機能を備えていることがよくあります。それを見つけるだけです。
盲目的に1.または2.しかないと仮定すると、テストコードまたは汚いリネンを公共の場で洗い流す厄介なクラスインターフェイスで生産ソフトウェアが肥大化する可能性があります。 * 8 ')
もちろん、プライベートメソッドを使用することも、テストすることもできます。
プライベートメソッドを実行するsome方法があります。その場合、その方法でテストできます。または、プライベートを実行するno方法があります。どちらの場合:一体それをテストしようとしているのか、いまいましいものを削除してください!
あなたの例では:
ええと、私はプライベートメソッドのみを持ち、イベントをリッスンすることによって他のオブジェクトと対話するオブジェクトを作成することが可能です。これは非常にカプセル化されますが、完全にテストできません。
なぜそれがテストできないのでしょうか?イベントに応じてメソッドが呼び出される場合は、テストでオブジェクトに適切なイベントをフィードするだけです。
それはプライベートメソッドを持たないことではなく、カプセル化を壊さないことです。プライベートメソッドを使用できますが、パブリックAPIを使用してテストする必要があります。パブリックAPIがイベントに基づいている場合は、イベントを使用します。
プライベートヘルパーメソッドのより一般的なケースでは、それらを呼び出すパブリックメソッドを通じてテストできます。特に、失敗したテストに合格するためのコードを書くことだけが許可されており、テストはパブリックAPIをテストしているため、通常、作成するすべての新しいコードはパブリックになります。プライベートメソッドは、既存のパブリックメソッドからプルされたとき、Extract Method Refactoringの結果としてのみ表示されます。しかしその場合、パブリックメソッドがプライベートメソッドを呼び出すため、パブリックメソッドをテストする元のテストはプライベートメソッドもカバーします。
したがって、通常、プライベートメソッドは、既にテスト済みのパブリックメソッドから抽出された場合にのみ表示されるため、すでにテスト済みでもあります。
コードで新しいクラスを作成するとき、いくつかの要件に答えるためにそれを行います。 要件はwhatではなく、コードが実行する必要があるhowです。これにより、ほとんどのテストがパブリックメソッドレベルで行われる理由を簡単に理解できます。
テストを通じて、コードが期待どおりの動作をすることを確認します、予期したときに適切な例外をスローするなど開発者がコードをどのように実装するかは、特に気にしません。実装、つまりコードがどのように機能するかは気にしませんが、プライベートメソッドのテストを避けることは理にかなっています。
パブリックメソッドがなく、イベントを介してのみ外部の世界とやり取りするクラスのテストについては、テストを介してイベントを送信し、応答をリッスンすることによってもテストできます。たとえば、クラスがイベントを受信するたびにログファイルを保存する必要がある場合、ユニットテストはイベントを送信し、ログファイルが書き込まれたことを確認します。
最後に重要なことですが、プライベートメソッドをテストすることが完全に有効な場合もあります。そのため、たとえば.NETでは、ソリューションがパブリックメソッドほど簡単ではない場合でも、パブリッククラスだけでなくプライベートクラスもテストできます。
プライベートメソッドはテストできないというのが私の理解です
私はそのステートメントに同意しません、または私はあなたがプライベートメソッドをテストしないと言います直接。パブリックメソッドは、さまざまなプライベートメソッドを呼び出すことができます。たぶん、作者は「小さな」メソッドを持ちたいと思って、コードの一部を巧妙に名付けられたプライベートメソッドに抽出しました。
Publicメソッドの記述方法に関係なく、テストコードはすべてのパスをカバーする必要があります。テスト後に、1つのプライベートメソッドの分岐ステートメント(if/switch)の1つがテストでカバーされていないことがわかった場合は、問題があります。ケースを見逃して実装が正しいOR実装が間違っており、そのブランチが実際に存在することはなかったはずです。
そのため、私はCoberturaとNCoverを頻繁に使用して、私のパブリックメソッドテストがプライベートメソッドもカバーしていることを確認しています。 OOプライベートメソッドを含むオブジェクトを自由に記述し、TDD /テストをそのような問題に陥らせないでください。
依存性注入を使用して、CUTが対話するインスタンスを提供する限り、サンプルは引き続き完全にテスト可能です。次に、モックを使用して、目的のイベントを生成し、CUTがその依存関係に対して正しいアクションを実行するかどうかを確認できます。
一方、イベントサポートが充実した言語を使用している場合は、少し異なる方法をとることがあります。オブジェクトがイベント自体をサブスクライブするときは気に入らず、代わりに、オブジェクトを作成するファクトリに、イベントをオブジェクトのパブリックメソッドにワイヤリングします。テストが簡単になり、CUTをテストする必要のあるイベントの種類を外部から確認できるようになります。
プライベートメソッドを使用して放棄する必要はありません。それらを使用することは完全に合理的ですが、テストの観点から、カプセル化を壊したり、クラスにテスト固有のコードを追加したりしないと、直接テストすることは困難です。トリックは、コードを汚したように感じるので、あなたが腸のうねりを作ろうとしていることがわかっているものを最小限にすることです。
これらは、実行可能なバランスを実現するために私が心がけていることです。
横向きに考えます。クラスを小さくし、メソッドを小さくして、多くの構成を使用します。それはより多くの仕事のように聞こえますが、最終的にはより個別にテスト可能な項目が得られ、テストはよりシンプルになり、実際の大きくて複雑なオブジェクトの代わりにシンプルなモックを使用するためのオプションが増えるでしょう。因数分解され、疎結合されたコード、さらに重要なことに、より多くのオプションを自分に与えます。物事を小さく保つことは、各クラスで個別にチェックする必要のあるものの数を減らし、クラスが大きくなり、多くの場合に時々発生する可能性があるコードスパゲッティを自然に減らす傾向があるため、最終的には時間を節約する傾向があります。内部的に相互依存するコードの動作。
ええと、私はプライベートメソッドのみを持ち、イベントをリッスンすることによって他のオブジェクトと対話するオブジェクトを作成することが可能です。これは非常にカプセル化されますが、完全にテストできません。
このオブジェクトはこれらのイベントにどのように反応しますか?おそらく、他のオブジェクトのメソッドを呼び出す必要があります。これらのメソッドが呼び出されるかどうかを確認することでテストできます。それがモックオブジェクトを呼び出すようにすれば、期待通りの動作をすることを簡単に主張できます。
問題は、オブジェクトと他のオブジェクトとの相互作用のみをテストすることです。オブジェクトの内部で何が起こっているかは気にしません。したがって、以前はこれ以上パブリックメソッドを使用するべきではありません。
私はこれと同じ問題にも苦労しました。本当に、それを回避する方法はこれです:プログラムの残りの部分がそのクラスとインターフェースすることをどのように期待しますか?それに応じてクラスをテストします。これにより、プログラムの残りの部分がクラスとどのようにインターフェースするかに基づいてクラスを設計する必要があり、実際、クラスのカプセル化と適切な設計が促進されます。
プライベート使用の代わりにデフォルト修飾子。次に、パブリックメソッドと組み合わせるだけでなく、それらのメソッドを個別にテストできます。これには、テストがメインコードと同じパッケージ構造を持つ必要があります。
通常、いくつかのプライベートメソッドは問題になりません。コードがパブリックメソッドにインライン化されているかのように、パブリックAPIを介してテストするだけです。プライベートメソッドの過剰mayは、凝集度が低いことを示しています。クラスは1つのまとまりのある責任を持つ必要があり、多くの場合、実際には存在しない場所にまとまりのある外観を与えるために、メソッドをプライベートにします。
たとえば、これらのイベントに応答して多くのデータベース呼び出しを行うイベントハンドラーがあるとします。イベントハンドラーをインスタンス化してデータベース呼び出しを行うのは明らかに悪い習慣であるため、データベースに関連するすべての呼び出しをプライベートメソッドにして、それらを実際に別のクラスに引き出す必要がある場合があります。
これは、TDDがカプセル化と対立していることを意味しますか?適切なバランスとは何ですか?私は現在、自分のメソッドのほとんどまたはすべてを公開する傾向があります。
TDDはカプセル化と対立しません。選択した言語に応じて、ゲッターメソッドまたはプロパティの最も単純な例を取り上げます。たとえば、Customerオブジェクトがあり、それにIdフィールドが必要だとします。最初に書くテストは、「customer_id_initializes_to_zero」のようなものです。実装されていない例外をスローするようにゲッターを定義し、テストの失敗を監視します。次に、そのテストに合格するために私ができる最も簡単なことは、ゲッターがゼロを返すようにすることです。
そこから、私は他のテストに進みます。おそらく、顧客IDが実際の機能的なフィールドであるテストです。ある時点で、ゲッターから返されるものを追跡するためにカスタマークラスが使用するプライベートフィールドを作成する必要があるでしょう。これを正確に追跡するにはどうすればよいですか?単純なバッキングintですか?文字列を追跡し、それをintに変換しますか? 20 intを追跡して平均化しますか?外の世界は気にしない-そしてあなたのTDDテストは気にしない。 カプセル化詳細です。
TDDを開始するときに、これが必ずしもすぐに明らかであるとは限らないと思います。つまり、メソッドが内部で実行することをテストするのではなく、クラスの細かい懸念をテストするのではありません。したがって、そのメソッドDoSomethingToFoo()
をテストしてバーをインスタンス化したり、メソッドを呼び出したり、プロパティの1つに2つを追加したりすることはありません。テストするのは、オブジェクト、一部の状態のアクセサーが変更されました(または変更されません)。これがテストの一般的なパターンです。「テスト中のクラスにXを実行すると、その後Yを観察できます」。 Yに到達する方法はテストの問題ではありません。これはカプセル化されるものであり、これがTDDがカプセル化と対立しない理由です。
使用を避ける?番号。
回避(で始まる?はい。
TDDを使用した抽象クラスを作成しても問題ないかどうかは質問していません。 TDD中に抽象クラスがどのように出現するかを理解している場合、同じ原則がプライベートメソッドにも適用されます。
プライベートメソッドを直接テストできないのと同じように、抽象クラスのメソッドを直接テストすることはできませんが、それが抽象クラスとプライベートメソッドから始めない理由です。具体的なクラスとパブリックAPIから始め、次に、一般的な機能をリファクタリングします。
クラスには要件があります。大まかに言えば、クラスには、要件に対応するパブリックメソッドがあり、他のメソッドはないはずです。
そして、あなたのクラスは要件を実装するためのコードを必要とします。要件によっては、多くのコードが必要になる場合があります。また、さまざまな理由から、メソッドが大きすぎてはいけません。
プライベートメソッドを要求しない場合は、すべてのコードをパブリックメソッドに配置する必要があります。したがって、適切なコードを含むクラスに必要な数だけ、プライベートメソッドを追加します。テスト容易性がすべてではありません。実際、優れたコーディング原則に違反していて、テストに合格するには常にバグが多いコードになってしまうと、テスト容易性は何にもなりません。
メソッドは、すべての古いコードがそれらを呼び出すのを防ぐためにプライベートにされています。これは、テストしたくないという意味ではありません。たとえば、MacOS/iOSでは、メソッドを@testableとしてマークするだけで、単体テストやその他のテストを構築するときはパブリックメソッドのように呼び出すことができますが、アプリケーションを構築するときは呼び出せません。