web-dev-qa-db-ja.com

偽造、モック、そしてスタブの違いは何ですか?

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

これが私の使い方です。

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

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

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

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

609
tvanfosson

あなたはいくつかの情報を得ることができます。

モックとスタブについてのMartin Fowlerから

オブジェクトには実際には実用的な実装がありますが、通常はショートカットを使用するとプロダクションには適しません。

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

モックはここで話しているものです:彼らが受けると予想される呼び出しの仕様を形成する予想で予めプログラムされたオブジェクト。

xunitpatternから

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

スタブ:この実装は、SUT内でテストされていないコード(Xページの製造上のバグを参照)を実行する値(または例外)でSUTからの呼び出しに応答するように設定されます。テストスタブを使用するための重要な指標は、SUTの間接入力を制御できないことが原因で未テストコードがあることです。

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

個人的に

MockとStubを使って単純化してみます。テストされたクラスに設定されている値を返すオブジェクトの場合は、Mockを使用します。私はStubを使用して、テスト対象のインターフェースまたは抽象クラスを模倣しています。実際、それはあなたがそれを呼んでいるものでは本当に重要ではありません、それらはプロダクションで使用されていないすべてのクラスであり、テストのためのユーティリティクラスとして使用されています。

479

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

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

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

テストダブルはスタブ、モック、偽物の総称です。しかし、非公式には、人々は単に彼らをモックと呼ぶのをよく聞くでしょう。

179
Mike

この質問がずっと前から出回っていて、 Roy Osheroveの "The Art of Unit Testing" に基づいた答えがまだ出ている人はいません。

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

スタブは、システム内の既存の依存関係(または共同作業者)を制御可能に置き換えるものです。スタブを使用することで、依存関係を直接扱わずにコードをテストできます。

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

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

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

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);

この場合、Assertfakeの値をチェックし、それを偽物にします。

さて、もちろんこれらの例は非常に工夫が凝っています、しかし私はこの区別に大きな利点を見ます。それはあなたが自分のものをどのようにテストしているのか、そしてあなたのテストの依存関係がどこにあるのかをあなたに知らせます。

私はOsheroveのことに同意します

純粋な保守容易性の観点から、私のテストではモックを使用することはそれらを使用しないことより多くの問題を引き起こします。それが私の経験でしたが、私はいつも新しいことを学んでいます。

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

私は、偽造品に対する主張を書くことが一般的なやり方であることを理解しています。私は古典派キャンプでMartin Fowlerとしっかりと提携していると思います( Martin Fowlerの "Mocks are not Stubs" を参照)。可能な限り偽物に対して主張することによってのみ行うことができます。

なぜここで定義されているようにモックを避けるべきなのかを楽しく読むためには、 "fowler mockist classicist"のグーグル。あなたはたくさんの意見を見つけるでしょう。

86
Marjan Venema

スタブとモックの使い方を説明するために、Roy Osheroveの「 単体テストの芸術 」に基づく例も含めたいと思います。

想像してみてください、私たちはログを印刷する唯一の機能を持っているLogAnalyzerアプリケーションを持っています。 Webサービスと通信する必要があるだけでなく、Webサービスがエラーをスローした場合、LogAnalyzerはエラーを別の外部依存関係に記録し、Webサービス管理者に電子メールで送信する必要があります。

LogAnalyzerの内部でテストしたいロジックは次のとおりです。

if(fileName.Length<8)
{
 try
  {
    service.LogError("Filename too short:" + fileName);
  }
 catch (Exception e)
  {
    email.SendEmail("a","subject",e.Message);
  }
}

Webサービスが例外をスローしたときにLogAnalyzerがEメールサービスを正しく呼び出すことをどのようにテストしますか?私たちが直面している質問は次のとおりです。

  • Webサービスをどのように置き換えることができますか?

  • Eメールサービスへの呼び出しをテストするために、Webサービスからの例外をどのようにシミュレートできますか?

  • 電子メールサービスが正しく呼び出されたこと、またはまったく呼び出されたことをどのように確認できますか。

最初の2つの質問には、 Webサービス用のスタブを使用して で対処できます。 3番目の問題を解決するには、 メールサービス用のモックオブジェクトを使用します

偽物とは、スタブまたはモックのいずれかを表すのに使用できる一般的な用語です。テストでは、2つの偽物があります。 1つは電子メールサービスのモックです。これは、正しいパラメータが電子メールサービスに送信されたことを確認するために使用します。もう1つは、Webサービスからスローされた例外をシミュレートするために使用するスタブです。テストが正しく実行されたことを確認するためだけに、Webサービスの偽物を使用してテスト結果を検証することはしないので、これはスタブです。私たちはそれに対して正しく呼ばれたと主張するので、電子メールサービスはモックです。

[TestFixture]
public class LogAnalyzer2Tests
{
[Test]
 public void Analyze_WebServiceThrows_SendsEmail()
 {
   StubService stubService = new StubService();
   stubService.ToThrow= new Exception("fake exception");
   MockEmailService mockEmail = new MockEmailService();

   LogAnalyzer2 log = new LogAnalyzer2();
   log.Service = stubService
   log.Email=mockEmail;
   string tooShortFileName="abc.ext";
   log.Analyze(tooShortFileName);

   Assert.AreEqual("a",mockEmail.To); //MOCKING USED
   Assert.AreEqual("fake exception",mockEmail.Body); //MOCKING USED
   Assert.AreEqual("subject",mockEmail.Subject);
 }
}
7
nanospeck

それはテストを表現力豊かにすることの問題です。テストで2つのオブジェクト間の関係を説明したい場合は、モックに期待を寄せます。テストでおもしろい動作をさせるために補助オブジェクトを設定している場合は戻り値をスタブします。

5
Steve Freeman

Arrange-Act-Assertに精通している場合、スタブとモックの違いを説明する1つの方法は、スタブが入力状態をアレンジするためであり、モックが結果をアサートするためのassertセクション.

ダミーは何もしません。これらは単にパラメータリストを埋めるためのものであり、未定義のエラーやnullエラーは発生しません。厳密に型付けされた言語で型チェッカーを満たすためにも存在しているので、コンパイルして実行することができます。

3
Sammi

あなたが主張していることは、モックオブジェクトと呼ばれていて、テストの実行を助けた他のすべてはスタブ

2

Robert C. Martin(Uncle Bob)による素晴らしい説明を得て、私は以下の資料から多くのことを学びました。

The Clean Codeブログのリトルモッカー

それはの違いと微妙さを説明します

  • ダミー
  • テストダブルス
  • スタブ
  • スパイ
  • (真)モック
  • 偽物

それはまたMartin Fowlerに言及し、それはソフトウェアテストの歴史の少しを説明します。

私はこのリンクを使ってこの質問に真の答えとして答えるつもりはありません。しかし、それは私がモックとスパイの概念をもっとよく理解するのを助けたので、私はそれがより多くの人々に役立つことを願ってこれに答えます。

1
Erik

スタブは、に基づいて応答を変えることができるという点でオブジェクトです。入力パラメータ両者の主な違いは、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;
 }

}