モックコンクリートクラス-非推奨


11

私は、「Growing Object-Oriented Software」の本の抜粋を読んだところです。これは、具象クラスのモックが推奨されない理由を説明しています。

以下に、MusicCentreクラスの単体テストのサンプルコードを示します。

public class MusicCentreTest {
  @Test public void startsCdPlayerAtTimeRequested() {
    final MutableTime scheduledTime = new MutableTime();
    CdPlayer player = new CdPlayer() { 
      @Override 
      public void scheduleToStartAt(Time startTime) {
        scheduledTime.set(startTime);
      }
    }

    MusicCentre centre = new MusicCentre(player);
    centre.startMediaAt(LATER);

    assertEquals(LATER, scheduledTime.get());
  }
}

そして彼の最初の説明:

このアプローチの問題は、オブジェクト間の関係が暗黙的に残されることです。モックオブジェクトを使用したテスト駆動開発の目的は、オブジェクト間の関係を発見することであることを明確にしたことを願っています。サブクラスを作成する場合、ドメインコードにはそのような関係を表示するものはなく、オブジェクトのメソッドだけです。これにより、この関係をサポートするサービスが他の場所に関連しているかどうかを確認するのが難しくなり、次回クラスで作業するときに分析をやり直す必要があります。

彼が言うとき、彼が何を意味するのか正確に理解することはできません。

これにより、この関係をサポートするサービスが他の場所に関連しているかどうかを確認するのが難しくなり、次回クラスで作業するときに分析をやり直す必要があります。

サービスはMusicCentreのメソッドに対応することを理解していますstartMediaAt

「他の場所」とはどういう意味ですか?

完全な抜粋はこちら:http : //www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html


彼がこれらの引用から何を意味するのか理解できなかったので、彼のブログにコメントを追加しました。
オリゴフレン

@oligofrenそれは本当に素晴らしい謎です:)
...-Mik378

回答:


6

その投稿の著者は、メンバークラスの使用よりもインターフェイスの使用を推奨しています。

It turns out that my MusicCentre object only uses the starting and stopping methods on the CdPlayer, the rest are used by some other part of the system. I'm over-specifying my MediaCentre by requiring it to talk to a CdPlayer, what it actually needs is a ScheduledDevice.

彼が後で再発見することを心配している関係は、MediaCentreクラスがCdPlayerオブジェクトのすべてを必要としないという事実です。彼の主張は、インターフェイスを使用することで(おそらく開始と停止に限定される)、インタラクションが実際に何であるかを理解しやすいということです。

「他の場所」とは、他のオブジェクトが同様に制限された関係を持つ可能性があることを意味し、完全なメンバーオブジェクトは必要ありません。インターフェイスを介してラップされる機能のサブセットで十分です。

すべての潜在的な機能を展開すると、クレームがより意味を持ち始めます。

  • 開始
  • やめる
  • 一時停止
  • 記録
  • ランダムプレイ順
  • サンプルトラック、曲の始まり
  • サンプルトラック、曲のランダムサンプル
  • メディア情報を提供する
  • ...

現在、「開始と停止が必要です」という彼の主張は、より理にかなっています。インターフェイスの代わりに具象メンバーオブジェクトを使用すると、将来の開発者にとって実際に必要なものが明確になりませ。CdPlayer内の他のすべての機能でMediaCentreからユニットテストを実行することは、「ドントケア」状態に属するため、テスト作業の無駄です。この場合、Record関数が機能していなかったとしても、それは必要ないので気にしません。しかし、将来のメンテナーは、書かれているように、コードに基づいてそれを必ずしも知っているとは限りません。

最終的に、著者の前提は、必要なものだけを使用し、以前の必要なものを将来のメンテナーに明確にすることです。目標は、その後のメンテナンス中にコードのモジュールの再作業/再分析を最小限にすることです。


この素晴らしい答えをありがとう。ただし、「他のすべての機能でユニットテストを実行することは、「ドントケア」状態に属するため、テスト作業の無駄です。」むしろ、「他の各機能のモックを作成することは、「ドントケア」状態に属しているため、テスト作業の無駄です。」
Mik378

@ Mik378-はい、それはまさに私が得ていたものです、私はそれを違う言い方で言いました。そして、それをより明確にするために答えを更新しました。

しかし、「ユニットテストの実行」という用語は紛らわしいと思います。これは、MusicCentreがコラボレーターのユニットテストを行うことを意味します...実際には、OWNサービスのユニットテストを行うために、コラボレーターをMOCKSします。ところで、私は今その意味を理解しています:)
Mik378

@ Mik378-同じことを言っているので、そうするためにおそらく正確な用語を使用していません。混乱をおologiesびします。

4

これにより、この関係をサポートするサービスが他の場所に関連しているかどうかを確認するのが難しくなり、次回クラスで作業するときに分析をやり直す必要があります。

それについて多くを考えた後、私はこの引用の可能な解釈を得る:

引用された「サービス」は「スケジューリングの事実」に対応しています。これは、「ScheduledDevice」という名前のよく知られた「1つの役割に焦点を合わせた」インターフェースで表現することも、インターフェイスに依存しない具体的なメソッド実装で暗黙的に表現することもできます。

上記のサンプルでは、​​スケジューリングはという名前のフル機能オブジェクト全体で表されていますCDPlayer。したがって、それはMusicCentre「スケジューリングの事実」との間の暗黙的な関係につながります。

したがって、具象クラスを注入し、それらを高レベルのオブジェクトにモックする場合、これらをテストする場合、注入された各「コンクリート」オブジェクトを分析して、それらが隠されている(暗黙的)ために特定の関係を示しているかどうかを確認する必要があります。それどころか、インターフェイスを介して常にコーディングすることにより、開発者は、どのような関係が高レベルのオブジェクトによって提供されるかを直接把握できるため、単体テストを分離するためにモックする必要がある機能を検出できます。


あなたは今それを持っていると思います。残念ながら、私はあなたのコメントの通知を受け取りませんでした。
スティーブフリーマン

3

ここで私が意味したサービスはCDPlayer.scheduleToStartAt()でした。それがMediaCentreが呼ぶもの、つまり機能するために必要な協力者です。MediaCentreはテスト対象のオブジェクトです。

アイデアは、MediaCentreが実装クラスではなく依存するものを明示する場合、その依存関係ロールに名前を付けてそれについて話すことができるということです。MediaCentreが知る必要があるのは、ScheduledDevicesと通信することだけです。システムの残りの部分が変更されると、機能が変更されない限り、MediaCentreを変更する必要はありません。

それは役立ちますか?


(この素晴らしい記事の著者:))私が解釈したかったのは次の文でした:「これにより、この関係をサポートするサービスが他の場所に関連するかどうかを確認することが難しくなり、次に作業するときに分析をやり直す必要がありますクラスで」。どんな分析?これは明らかに隠されているので、どのオブジェクトのメソッドを検出するという事実が関係を実装することになっていますか?
-Mik378
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.