Modelクラスをテストドライブ(または少なくとも単体テストを作成)しようとしていますが、クラスが結合しすぎていることに気付きました。この結合を壊すことができないので、ユニットテストを書くことはますます難しくなっています。
具体的には:
モデルクラス:これらは私のアプリケーションのデータを保持するクラスです。それらはPOJO(プレーンな古いJavaオブジェクト))によく似ていますが、いくつかのメソッドもあります。アプリケーションが大きすぎないため、約15のモデルクラスがあります。
カップリング:例を挙げると、注文ヘッダー->注文アイテムの単純なケースを考えてみてください。ヘッダーはアイテムを認識し、アイテムはヘッダーを認識します(特定の操作を実行するには、ヘッダーからの情報が必要です)。次に、注文アイテム->アイテムレポートの間に関係があるとします。アイテムレポートにはアイテムも必要です。この時点で、アイテムレポートのテストを書くことを想像してください。テストを実行するには、注文ヘッダーが必要です。これは3つのクラスを持つ単純なケースです。クラスが増えると、事態はさらに複雑になります。
アルゴリズム、永続化レイヤー、UIインタラクションなどを設計するときに分離されたクラスを思い付くことができますが、モデルクラスでは、それらを分離する方法を考えることができません。彼らは現在、相互に依存するクラスの大きな塊として座っています。
これが私が考えることができるいくつかの回避策です:
モデルクラスでこの結合を解除する方法について他のアイデアはありますか?または、モデルクラスの単体テストを簡単にする方法は?
回答を確認してから更新:
クラスは本当に分離する必要がありますか?あなたの例では、ビジネスの観点から、注文ヘッダーと注文アイテムはエンティティであり、非常に近いものです。それらはおそらく aggregate を形成します。したがって、それらを分離しようとすると、不必要な複雑さが生じ、モデルの読み取りが混乱します。
これを解決するには、コード内で集計を見つけて、集計全体を単体テストします。
話を簡単にするためにシナリオを簡略化しようとしているのはわかっていますが、なぜOrderItemはヘッダーを気にするのですか?ヘッダーはアグリゲーター(DDDでは「ルート」と呼ばれます)であり、そのコンポーネント(OrderItemはその1つです)について知る責任があります。
たとえば、特定のアイテムが10個以上含まれている注文に割引が適用されるなどの特殊なケースについて話し合っている場合、注文の処理中にどの割引が適用されるかを見つける割引サービスなどの仕事になります。
同じことがItemReportにも当てはまります...それは、アイテムの選択、フィルタリング、順序付けなどのルールを知る責任があります。アイテムはレポートに関係するべきではありません。それはその仕事ではありません。
モデルクラスでこの結合を解除する方法について他のアイデアはありますか?または、モデルクラスの単体テストを簡単にする方法は?
私の意見では、インターフェースに対するコーディングが進むべき道です。言い換えれば、設計によってコードを分離することは、現代のプロジェクトが従うアプローチです。これは、nit-testingのニーズに大いに役立ちます。
言い換えると、開発を計画している、または依存関係を削除するために分離しようとしているソフトウェアコンポーネントに対して、正式で正確かつ検証可能なインターフェイス仕様を定義することをお勧めします。
これを行う1つの方法は、あなたが言ったように、クラス間にインターフェースを作成することです。各クラスは、その依存関係を、単体テストコンテキストでモックまたはスタブできるインターフェイス参照として受け取ります。これにより、各クラスに必要な設計のessential部分についてもう少し考えるようになるかもしれません。たとえば、注文アイテムに完全な注文ヘッダーが必要ない場合があります。このプロセスでは、設計の潜在的な概念を発見する可能性があります。これにより、再利用の可能性が高まり、意図に沿った要素がよりインラインで作成されます。またはraison d'être。
一方、インターフェースを作成することは、そのような相乗的で結合された概念にとっては奇妙に思えるかもしれません。その場合は、 流暢なテストデータビルダー を使用して、ドメイン固有の直接的な方法を作成し、依存オブジェクトを簡単に作成できます。これらのビルダーは、依存オブジェクトを作成するためのテストコードによって使用されるため、直接テストする必要はありません。