単体テストの依存関係 (Doctrine など) を偽装するか、実際の依存関係を使用する方が良いですか?
2 に答える
単体テストでは、クラスの実際のインスタンスを 1 つだけ使用します。それがテスト対象のクラスです。
理由がない限り、そのクラスのすべての依存関係をモックする必要があります。
モックを作成しない理由は、それ自体に依存関係がないデータ オブジェクトが使用されている場合です。実際のオブジェクトを使用して、後で正しいデータを受信したかどうかをテストできます。
モックを作成しないもう 1 つの理由は、モックの構成が複雑すぎる場合です。その場合、代わりにコードをリファクタリングする理由があります。クラスのモックが複雑すぎる場合、そのクラスの API が複雑すぎる可能性があるためです。それも。
しかし、一般的な答えは次のとおりです。毎回、すべての依存関係を常にモックする必要があります。
「複雑すぎてリファクタリングが難しい」ケースの例を紹介します。
モデルの内部データ ストレージに「Zend_Session_Namespace」オブジェクトを使用していました。そのインスタンスはモデルに注入されたので、モックは問題になりませんでした。
しかし、実際の「名前空間」クラスの内部実装により、すべての呼び出しを、モデルでの使用方法の正しい順序でモックすることができ__set
まし__get
た。そして、それはひどいものでした。コード内の値の読み取りと書き込みの順序を変更するたびに、テストでモックを変更する必要がありましたが、何も壊れていませんでした。コードのリファクタリングによってテストが壊れたり、強制的に変更されたりすることはありません。
リファクタリングにより、「Zend_Session_Namespace」をモデルから分離する新しいオブジェクトが追加されました。「ArrayObject」を拡張し、「名前空間」を含むオブジェクトを作成しました。作成時に、すべての値が Namespace から読み取られて ArrayObject に追加され、書き込みのたびに、値が Namespace オブジェクトにも渡されます。
すべてのテストで実際に拡張された ArrayObject を使用できる状況になりました。それ自体は、「Zend_Session_Namespace」の未構成のモック インスタンスのみを必要としていました。モデルをテストしました。モデル内で使用されるデータ ストアのみが必要でした。
セッションが正しく読み書きされることをテストするために、その ArrayObject 自体をテストします。
したがって、最終的には、モデルの実際のインスタンスと、データ ストアの実際のインスタンスを、何もしない "Zend_Session_Namespace" のモック インスタンスと一緒に使用しています。これまでモデルクラスに混在していた「モデルもの」と「セッション保存のもの」をあえて分離→「単一責任原則」にしました。
そのようにして、テストは本当に簡単になりました。そして、これもコードのにおいだと思います。モック クラスの作成と構成が複雑な場合、またはテスト対象のクラスを変更するときに多くの変更が必要な場合は、リファクタリングを検討する時期です。そこには何か問題があります。