840

これらの用語の使い方は知っていますが、単体テストの偽造、モック、スタブの定義が受け入れられているかどうか疑問に思っますか?テスト用にこれらをどのように定義しますか?それぞれを使用する可能性のある状況を説明してください。

これが私がそれらを使用する方法です:

偽物:インターフェイスを実装するが、固定データを含み、ロジックを含まないクラス。実装に応じて、単に「良い」または「悪い」データを返します。

モック:インターフェースを実装し、特定のメソッドからスローする戻り値/例外を動的に設定する機能を可能にし、特定のメソッドが呼び出されたかどうかをチェックする機能を提供するクラス。

スタブ:モッククラスと似ていますが、メソッドが呼び出されたかどうかを確認する機能がない点が異なります。

モックとスタブは、手動で生成することも、モックフレームワークによって生成することもできます。偽のクラスは手作業で生成されます。私は主に、クラスと依存クラス間の相互作用を検証するためにモックを使用します。相互作用を検証し、コードを介して代替パスをテストしたら、スタブを使用します。私は主にデータの依存関係を抽象化するため、またはモック/スタブが毎回設定するのが面倒な場合に、偽のクラスを使用します。

4

14 に答える 14

623

いくつかの情報を得ることができます:

Mockと Stub について Martin Fowler より

のオブジェクトには実際に機能する実装がありますが、通常は何らかのショートカットを使用するため、本番環境には適していません

スタブは、テスト中に行われた呼び出しに対して定型の回答を提供します。通常、テスト用にプログラムされたもの以外にはまったく応答しません。スタブは、「送信した」メッセージや、「送信した」メッセージの数だけを記憶する電子メール ゲートウェイ スタブなど、呼び出しに関する情報も記録する場合があります。

ここで話しているのはモックです。つまり、受け取ると予想される呼び出しの仕様を形成する期待値で事前にプログラムされたオブジェクトです。

xunitpatternから:

Fake : SUT が依存するコンポーネントによって提供されるものと同じ機能の非常に軽量な実装を取得または構築し、SUT に本物の代わりにそれを使用するように指示します。

Stub : この実装は、SUT 内でテストされていないコード (X ページのプロダクション バグを参照) を実行する値 (または例外) を使用して、SUT からの呼び出しに応答するように構成されています。テスト スタブを使用する重要な兆候は、SUT の間接入力を制御できないためにコードがテストされていないことです。

SUT (System Under Test) が依存するオブジェクトと同じインターフェースを実装するモック オブジェクト。SUT でメソッドを呼び出すことの副作用を観察できないために未テストの要件 (X ページのプロダクション バグを参照) が発生するのを避けるために動作検証を行う必要がある場合、モック オブジェクトを観察ポイントとして使用できます。

個人的に

モックとスタブを使用して単純化しようとしています。テストされたクラスに設定された値を返すオブジェクトである場合は、Mock を使用します。Stub を使用して、テスト対象のインターフェイスまたは抽象クラスを模倣します。実際、それを何と呼ぶか​​は問題ではありません。これらはすべて本番環境では使用されず、テスト用のユーティリティ クラスとして使用されるクラスです。

于 2008-12-06T16:17:52.617 に答える
259

Stub - メソッド呼び出しに対して定義済みの応答を提供するオブジェクト。

モック- 期待値を設定するオブジェクト。

Fake - 機能が制限されたオブジェクト (テスト目的)。たとえば、偽の Web サービス。

Test Double は、スタブ、モック、フェイクの総称です。しかし、非公式には、人々が単にそれらをモックと呼んでいるのをよく耳にします。

于 2011-03-03T11:45:01.110 に答える
113

この質問が非常に長い間存在し、 Roy Osherove の "The Art of Unit Testing" に基づいた答えをまだ誰も提供していないことに驚いています。

「3.1 スタブの紹介」では、スタブを次のように定義しています。

スタブは、システム内の既存の依存関係 (またはコラボレーター) の制御可能な代替品です。スタブを使用すると、依存関係を直接処理せずにコードをテストできます。

また、スタブとモックの違いを次のように定義しています。

モックとスタブについて覚えておくべき主なことは、モックはスタブと同じですが、モック オブジェクトに対してアサートするのに対し、スタブに対してアサートしないということです。

Fake は、スタブとモックの両方に使用される名前です。たとえば、スタブとモックの違いを気にしない場合などです。

Osherove がスタブとモックを区別する方法は、テスト用の偽物として使用されるクラスは、スタブまたはモックの両方である可能性があることを意味します。どちらが特定のテストに適しているかは、テストでチェックをどのように記述するかによって完全に異なります。

  • テストがテスト中のクラスの値をチェックするとき、または実際には偽物以外の場所で、偽物がスタブとして使用されました。テスト対象のクラスが使用する値を提供しただけで、呼び出しによって返された値を介して直接、または呼び出しの結果として (何らかの状態で) 副作用を引き起こすことによって間接的に行われます。
  • テストが偽物の値をチェックするとき、それはモックとして使用されました。

クラス FakeX がスタブとして使用されるテストの例:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, cut.SomeProperty);

はまったく使用しないため、fakeインスタンスはスタブとして使用されます。Assertfake

テスト クラス X がモックとして使用されるテストの例:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, fake.SomeProperty);

この場合、Assertは の値をチェックしfake、その偽物をモックにします。

もちろん、これらの例は非常に不自然ですが、この区別には大きなメリットがあると思います。これにより、自分のものをどのようにテストしているか、およびテストの依存関係がどこにあるかを認識できます。

Osherove の意見に同意する

純粋な保守性の観点から、モックを使用した私のテストでは、モックを使用しない場合よりも多くの問題が発生します。それが私の経験ですが、私は常に何か新しいことを学んでいます。

偽物に対するアサートは、テスト対象ではないクラスの実装にテストが大きく依存するようになるため、避けたいものです。これは、クラスActualClassUnderTestの実装がClassUsedAsMock変更されたため、クラスのテストが壊れ始める可能性があることを意味します。そして、それは私に悪臭を放ちます。のテストは、が変更されたActualClassUnderTest場合にのみ中断する必要があります。ActualClassUnderTest

フェイクに対して assert を書くことは、特に TDD サブスクライバーのモックイスト タイプの場合は一般的であることを認識しています。私は、古典派の陣営で Martin Fowler にしっかりと賛成しており ( Martin Fowler の「モックはスタブではない」を参照)、Osherove と同様に、相互作用テスト (偽物に対してアサートすることによってのみ実行できます) をできるだけ避けています。

ここで定義されているモックを避けるべき理由を楽しく読むには、「fowler mockist classicist」をググってください。たくさんの意見が見られます。

于 2015-10-25T18:03:35.553 に答える
69

最多投票の回答で言及されているように、Martin Fowler はMocks Arent Stubsでこれらの違いについて説明しています。

これらがどのように違うのかということに焦点を当てるよりも、なぜこれらが異なる概念なのかということに焦点を当てる方が啓発的だと思います。それぞれが異なる目的のために存在します。

偽物

偽物は、「自然に」動作する実装ですが、「本物」ではありません。これらはあいまいな概念であり、人によって何が偽物であるかについての理解が異なります。

偽物の一例は、メモリ内データベースです (:memory:ストアで sqlite を使用するなど)。これを本番環境で使用することはありませんが (データが永続化されないため)、テスト環境で使用するデータベースとしては完全に適切です。また、「実際の」データベースよりもはるかに軽量です。

別の例として、本番環境ではある種のオブジェクト ストア (Amazon S3 など) を使用しているかもしれませんが、テストではオブジェクトをディスク上のファイルに単純に保存できます。「ディスクに保存」の実装は偽物になります。(または、代わりにメモリ内ファイルシステムを使用して、「ディスクに保存」操作を偽造することもできます。)

3 番目の例として、キャッシュ API を提供するオブジェクトを想像してください。正しいインターフェイスを実装しているが、単にキャッシュをまったく実行せず、常にキャッシュ ミスを返すオブジェクトは、一種の偽物です。

フェイクの目的は、テスト対象のシステムの動作に影響を与えることではなく、テストの実装を簡素化することです (不要または重い依存関係を削除することによって)。

スタブ

スタブは、「不自然に」動作する実装です特定の出力で特定の入力に応答するように (通常はテスト セットアップによって) 事前に構成されています。

スタブの目的は、テスト中のシステムを特定の状態にすることです。たとえば、REST API とやり取りするコードのテストを作成している場合、定型応答を常に返す API や特定のエラーで API 要求に応答する API を使用して REST API をスタブ化できます。このようにして、システムがこれらの状態にどのように反応するかについてアサーションを行うテストを作成できます。たとえば、API が 404 エラーを返した場合にユーザーが受け取る応答をテストします。

通常、スタブは、応答するように指示した正確な対話にのみ応答するように実装されます。しかし、何かをスタブにする重要な機能はその目的です。スタブとは、テスト ケースを設定することです。

モック

モックはスタブに似ていますが、検証が追加されています。モックの目的は、テスト対象のシステムが依存関係とどのように相互作用したかについてアサーションを作成することです。

たとえば、ファイルを Web サイトにアップロードするシステムのテストを作成している場合、ファイルを受け入れ、アップロードされたファイルが正しいことをアサートするために使用できるモックを作成できます。または、小規模では、オブジェクトのモックを使用して、テスト対象のシステムがモックされたオブジェクトの特定のメソッドを呼び出すことを確認するのが一般的です。

モックは、特定のテスト方法である相互作用テストに関連付けられています。システムの相互作用よりもシステムの状態をテストすることを好む人は、仮にあったとしてもモックをあまり使用しません。

テストダブルス

フェイク、スタブ、モックはすべて、テスト ダブルのカテゴリに属します。テストダブルは、他の何かの代わりにテストで使用するオブジェクトまたはシステムです。ほとんどの自動化されたソフトウェア テストでは、何らかのテスト ダブルが使用されます。他の種類のテスト ダブルには、ダミー値スパイ、および I/Oブラックホールが含まれます。

于 2019-03-06T19:05:28.267 に答える
14

Unit testing-ユニット(クラス、メソッド)が制御されているテストのアプローチです。

Test double- プライマリ オブジェクトではありません (OOP の世界から)。これは、テスト、チェック、または開発中に一時的に作成される認識です。そして、それらは テストされたユニット(メソッド、クラス...)の依存関係を閉じるために作成されます

ダブルス タイプのテスト:

  • fake object依存関係を作成するために使用できる継承または他のアプローチを使用しているインターフェース(プロトコル)または拡張の実際の実装です。通常、依存関係を置き換えるための最も簡単なソリューションとして開発者によって作成されますis

  • stub object戻り値を定義するために(開発者によって)事前定義された余分な状態を持つ裸のオブジェクト(0、nil、およびロジックのないメソッド)です。通常、フレームワークによって作成されます

class StubA: A {
    override func foo() -> String {
        return "My Stub"
    }
}
  • mock objectと非常に似てstub objectいますが、プログラムの実行中に追加の状態が変更され、何かが発生したかどうかを確認します(メソッドが呼び出された、引数、いつ、どのくらいの頻度で...)。
class MockA: A {
    var isFooCalled = false
    override func foo() -> String {
        isFooCalled = true
        return "My Mock"
    }
}
  • spy object「部分的なモッキング」を持つ実際のオブジェクトです。これは、モックされた動作を除いて、 double 以外のオブジェクトを操作することを意味します

  • dummy objectテストを実行するために必要なオブジェクトですが、このオブジェクトの変数またはメソッドが呼び出されていません。

スタブとモック

マーティン・ファウラーは言った

スタブは状態検証を使用するのに対し、モックは動作検証を使用するという違いがあります。

【モッキートモックvsスパイ】

于 2020-04-14T14:10:21.777 に答える
6

テストを表現力豊かにすることが問題です。テストで 2 つのオブジェクト間の関係を記述したい場合は、モックに期待値を設定します。サポート オブジェクトを設定してテストで興味深い動作を取得する場合は、戻り値をスタブします。

于 2009-05-21T18:36:11.353 に答える
3

スタブフェイクは、入力パラメーターに基づいて応答を変えることができるという点でオブジェクトです。それらの主な違いは、Fake はスタブよりも現実世界の実装に近いということです。スタブには、予想される要求に対する基本的にハードコードされた応答が含まれます。例を見てみましょう:

public class MyUnitTest {

 @Test
 public void testConcatenate() {
  StubDependency stubDependency = new StubDependency();
  int result = stubDependency.toNumber("one", "two");
  assertEquals("onetwo", result);
 }
}

public class StubDependency() {
 public int toNumber(string param) {
  if (param == “one”) {
   return 1;
  }
  if (param == “two”) {
   return 2;
  }
 }
}

モックは、偽物やスタブから一歩進んだものです。モックはスタブと同じ機能を提供しますが、より複雑です。API のメソッドを呼び出す順序を指定するルールを定義できます。ほとんどのモックは、メソッドが呼び出された回数を追跡でき、その情報に基づいて対応できます。モックは通常、各呼び出しのコンテキストを認識しており、さまざまな状況で異なる反応を示すことができます。このため、モックには、モックしているクラスに関するある程度の知識が必要です。通常、スタブは、メソッドが呼び出された回数や、一連のメソッドが呼び出された順序を追跡できません。モックは次のようになります。

public class MockADependency {

 private int ShouldCallTwice;
 private boolean ShouldCallAtEnd;
 private boolean ShouldCallFirst;

 public int StringToInteger(String s) {
  if (s == "abc") {
   return 1;
  }
  if (s == "xyz") {
   return 2;
  }
  return 0;
 }

 public void ShouldCallFirst() {
  if ((ShouldCallTwice > 0) || ShouldCallAtEnd)
   throw new AssertionException("ShouldCallFirst not first thod called");
  ShouldCallFirst = true;
 }

 public int ShouldCallTwice(string s) {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallTwice called before ShouldCallFirst");
  if (ShouldCallAtEnd)
   throw new AssertionException("ShouldCallTwice called after ShouldCallAtEnd");
  if (ShouldCallTwice >= 2)
   throw new AssertionException("ShouldCallTwice called more than twice");
  ShouldCallTwice++;
  return StringToInteger(s);
 }

 public void ShouldCallAtEnd() {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallAtEnd called before ShouldCallFirst");
  if (ShouldCallTwice != 2) throw new AssertionException("ShouldCallTwice not called twice");
  ShouldCallAtEnd = true;
 }

}
于 2018-11-12T21:46:58.980 に答える
2

「ウラジミール・コリコフによるユニットテストの原則、実践、およびパターン」という本によると:

  • モック:発生する相互作用をエミュレートして調べるのに役立ちます。これらの相互作用は、状態を変更するために SUT が依存関係に対して行う呼び出しです。つまり、SUT とその依存関係の相互作用 (動作) を調べるのに役立ちます。モックは次のようになります。
    1. Spy : 手動で作成
    2. モック : フレームワークを使用して作成
  • スタブ:着信インタラクションをエミュレートするのに役立ちます。これらの相互作用は、入力データを取得するために SUT がその依存関係に対して行う呼び出しです。つまり、SUT に渡されたデータをテストするのに役立ちます。3種類になりそう
    1. Fake: 通常、まだ存在しない依存関係を置き換えるために実装されます。
    2. ダミー: ハードコーディングされた値です。
    3. スタブ: さまざまなシナリオでさまざまな値を返すように構成する本格的な依存関係。
于 2021-12-06T19:31:13.330 に答える