17

私のチームの TDD の進化には、従来の oop からの逸脱と思われるものが含まれています。

  1. 自己完結型のクラスからの脱却 現在も、必要に応じてデータをカプセル化しています。しかし、ヘルパークラスをモックするために、通常、コンストラクターまたはミューテーターを介して外部から設定する方法を作成します。

  2. プライベート メソッドは使用しません。モッキング フレームワーク (RhinoMocks) を利用するために、メソッドを非公開にすることはできません。これは、従来の開発者に「売り込む」最大のものでした。そしてある程度、私は彼らの主張を理解しています。私はもっ​​とテストすることを大切にしています。

あなたの考えは何ですか?

4

15 に答える 15

24

OOP は、可能な多くのパラダイムの 1 つにすぎません。それ自体は目的ではなく、目的を達成するための手段です。他のパラダイムの方が適している場合は、オブジェクト指向でプログラミングする必要はありません。

また、ユニット テストはオブジェクト指向言語よりも関数指向言語の方がはるかに簡単になる傾向があると指摘する前に、無数の賢明な人々が述べています。これは、テストの自然な単位が関数であるためです。これはクラス (プライベート メソッドやあらゆる種類の奇妙な状態を持つ可能性がある) ではなく、関数です。

一方、テスト容易性はそれ自体に価値があります。コードがテスト可能でない場合、それをテストすることはできません (当然のことです)。したがって、どちらか一方の極端を選択する必要がある場合、私は間違いなくテスト容易性を選択します。

しかし、明らかな疑問は、本当にすべてのプライベート メソッドをテストする必要があるかということです。これらはクラスのパブリック コントラクトの一部ではなく、単独では意味がない場合があります。パブリック メソッドは、特定の目的を持っているため、テストすることが重要です。これらは、この非常に特定のコントラクトを満たし、オブジェクトを一貫した状態にしておく必要があります。それらは本質的にテスト可能であり、プライベート メソッドはそうではないかもしれません。(プライベート メソッドが何をするかは誰が気にしますか? クラス コントラクトの一部ではありません)

おそらく、より良い解決策は、それ以外の場合はプライベートなものの一部を別のクラスにリファクタリングすることです。おそらく、プライベート メソッドをテストする必要性は、あなたが考えているほど大きくはありません。

別の注意として、他のモッキング フレームワークでは、プライベートなものもモックできます。

編集: もう少し考えた後、プライベート メンバーを公開するだけではおそらく恐ろしい考えであることを強調したいと思います。そもそもプライベート メンバーを使用する理由は次のとおりです。クラスの不変条件は常に維持する必要があります。外部コードがクラスを無効な状態にすることは不可能でなければなりません。それは単なる OOP ではなく、常識でもあります。プライベート メソッドは、クラス内で内部的により細かい粒度を許可するためのものであり、複数のメソッドにまたがるいくつかのタスクを除外するなどですが、通常はそうではありません。クラス不変を保持します。彼らは仕事の半分を行い、残りの半分を行うために後で呼び出される他のプライベート メソッドに依存します。一般的にはアクセスできないため、安全です。それらを呼び出すことができるのは他のクラス メソッドだけなので、それらが不変条件を保持している限り、すべて問題ありません。

そうです、プライベート メソッドをパブリックにすることでテスト可能にしますが、単体テストでは簡単に発見できないバグの原因にもなります。クラス「間違った」を使用できるようにします。適切に設計されたクラスは、外部コードでどのように使用されても、常にその不変条件を維持します。すべてを公開すると、それはもはや不可能です。外部コードは、そのコンテキストで使用されない可能性があり、クラスを無効な状態にスローする内部ヘルパー関数を呼び出すことができます。

そして、単体テストは、これが起こらないことを本当に保証することはできません. したがって、予想よりもはるかに大きなエラーの原因を導入するリスクがあると思います.

もちろん、上記のプライベート メンバー (クラスの不変条件を保持しないもの) の定義を考えると、他の多くのメソッドを安全に public にすることが可能かもしれませ。それらを外部コードから。そのため、プライベート メソッドを少なくすることで問題を軽減できますが、すべてがパブリックである場合に可能になるように、外部コードがクラスを壊すことはありません。

于 2008-11-14T17:41:53.457 に答える
14

私はライノモックに詳しくなく、実際にモッキングツールを使用したり必要としたりしたことがないため、ここではベースから外れている可能性がありますが、

  • OO 原則と TDD の間に矛盾があってはなりません。
  • プライベート メソッドは単体テストする必要はなく、パブリック メソッドのみをテストする必要があります
于 2008-11-14T17:33:12.880 に答える
9

あなたが経験しているのは、テストが設計に力を加えているということです。これが実際に、TDD が主に設計戦略である理由です。注意を払い、兆候を読み取る方法を知っていれば、テストを作成することで、より適切に分離された設計が強制されます。

クラスに「ヘルパー オブジェクト」を注入することは、実際には良いことです。ただし、それらをヘルパーオブジェクトと考えるべきではありません。それらは通常のオブジェクトであり、うまくいけば異なる抽象化レベルにあります。それらは基本的に戦略であり、より高いレベルのアルゴリズムの詳細がどのように埋められるかを構成します。私の経験では、嘲笑もやり過ぎになる可能性があります。このトピックに関する興味深い考えについては、http://martinfowler.com/articles/mocksArentStubs.htmlをご覧ください。

プライベート メソッドに関しては、これがあなたのモッキング フレームワークとどう関係するのか完全には理解できません。通常は、パブリック コントラクトの一部であるパブリック メソッドのみを持つインターフェイスをモックする必要があります。

とにかく、私の意見では、複雑なプライベート メソッドはコードの臭いです。これは、クラスがおそらく責任を負いすぎており、単一責任の原則に違反していることを示しています。公開することが実際にカプセル化の違反にならないクラスの種類を考えてください。メソッドをそのクラスに移動する (おそらく途中で作成する) と、結合と結束の点で設計が改善される可能性があります。

于 2008-11-14T20:57:58.240 に答える
5

優れた OO 設計とは、カプセル化やプライベート メソッドを持つことではありません。

主要な設計上の臭いの 1 つは、システムのさまざまな部分間の結合です。ヘルパー クラスをオブジェクトに注入してテストする前は、オブジェクトはどのようにしてヘルパーにアクセスしていたのでしょうか?

私の推測では、依存性注入に切り替えることで、システム内の結合が低下したと思います。

オープン/クローズの原則もあります。ヘルパー クラスを注入することで、動作のポリモーフィックな置換が可能になります。

また、非プライベート メソッドをクラスで可視化することに懸念がある場合は、インターフェイスを介してクラスを使用します。とにかく、これは良い考えですよね?

于 2008-11-14T18:21:36.137 に答える
5

メンテナンス性の方が重要です。

単体テストと OOP の両方がその目標を共有しているという点をお見逃しなく。

于 2008-11-14T18:28:46.090 に答える
3

OOP はツールであり、目的ではありません

于 2008-11-14T18:42:05.987 に答える
1

私はRhinoMocksを使用しており、多くのプライベートメソッドを使用しています。私は通常、他のクラスではなくインターフェースに依存するようにクラスを作成します。これにより、モックが簡単になります。

于 2008-11-14T17:44:58.893 に答える
1

クラススコープに関しては、内部を使用してフレームワークを簡素化し(エンドユーザー向け)、フレームワークプロジェクトAssemblyInfo.csで指定できます。

[assembly: InternalsVisibleTo("MyAssembly.Tests")]
于 2008-11-14T17:55:52.990 に答える
1

依存性注入と制御の反転は、両方の世界を最大限に活用するためのかなり良い方法です。優れた設計は、さまざまな方法 (テスト) でコードを使用する能力を制限するべきではなく、コードを改善する必要があります。

私たちは今、DI/IOC を使用するようにたくさんのシングルトンを書き直しています。

于 2008-11-14T17:35:16.760 に答える
1

一部のヘルパー クラスを外部化する方法として、依存性注入を調査することもできます。

于 2008-11-14T17:36:23.933 に答える
1

プライベート メソッドなどの使用を制限するフレームワークがある場合は、それを削除します。限目。これは、ほとんどの言語で必要とされる基本的なことの 1 つです。

于 2008-11-14T17:40:26.190 に答える
1

私はそれらすべての間の対立に精通していません。高い凝集度と低いカップリングは OO の核心であり、たまたまテストの核心でもあります。

于 2008-11-14T18:41:18.423 に答える
0

privateキーワードの代わりにマクロを使用してみませんか。「testmode」をオンにしてコンパイルすると、これらのメソッドはパブリックになります。それ以外の場合はプライベートです。マクロを使用すると、テストモードでコンパイルしないと、プライベートメソッドをパブリックに使用するときに、コンパイラの警告が表示されます。プライベートメソッドがユニットテストに失敗しても、プログラムにバグがあることを意味するわけではありませんが、CauseBSOD呼び出されることのない関数""を使用するのと同じである可能性があります。これは非常に壊れた機能です(BSODを引き起こすことは意図されていないと仮定します)が、ユーザーに関する限り、バグではありません。

于 2008-11-14T19:25:27.910 に答える
0

テストクラスだけのフレンドクラスを使えないのはなぜですか? または、プライベート メンバーを持つ親クラスからテスト クラスを派生させます。

私の意見では、悪いテストツールに対応するためにすべてを公開することは間違いです。他の人が言ったように、これは選択である必要はありません。優れたソフトウェアを設計します。十分にテストし、優れたツールを使用してください。よく知られているテスト ツールのベスト プラクティスを破る必要がある場合は、テスト ツールを再考する必要があります。

于 2008-11-14T21:04:15.217 に答える
0

Intellisense の通常のユーザーとして、すべてのメソッドがパブリックであるという要件に気が狂いそうになります。個人的には、その根拠だけで OOP に固執します。

于 2008-11-14T17:33:37.980 に答える