モックとスタブの違いは何ですか?


963

Martin FowlerのMocks Aren's Stubsを含む、テストにおけるモッキングとスタブについてのさまざまな記事を読みましたが、その違いはまだわかりません。



75
@OP違いがないので。この記事は、コミュニティに愛されているのと同じくらい、敬意を表して、他の方法では理解しやすい単語に意味を付け加えたり、物事を複雑にしたりすることによって、すべてを不必要に混乱させています。モックは単なるモックであり、実際のものではなく偽のビジネスロジックを実行するものです。最後に動作をチェックするのはあなたの選択ですが、それでもモックです。またはあなたがそれを呼び出したいものなら何でも、それを1つにしてください。髪を分割しないでください。シンプルにして、人々があなたのコンセプトを簡単に理解できるようにします-上記の記事は失敗します。
2016年

10
「モック、偽物、およびスタブ間の分類は、文献全体で非常に一貫していません。」多くの引用あり。まだ私のお気に入りのWikipedia引用の1つ-そのようなものが存在する場合:) en.wikipedia.org/wiki/Mock_object
JD。

11
マーティンファウラーの記事は、初心者には理解しにくいことです。
lmiguelvargasf 2016年

1
私が理解している方法は、スタブはダミーデータのコレクションのように、単にテスト用の使い捨てオブジェクトになるということです。Mockは、テスト用に動作を変更した可能性のある、さまざまなメソッドを持つサービスレイヤーなど、より複雑なものの巧妙にオーバーライドされたバージョンになります。2つのものが一緒に使用されます。スタブされたオブジェクトをモックレイヤーに渡すことができます。
JsonStatham

回答:


746

スタブ

最大の違いは、あなたがすでに所定の動作で書いたスタブであることだと思います。したがって、テスト目的で偽装している依存関係を実装するクラス(抽象クラ​​スまたはインターフェイスの可能性が最も高い)があり、メソッドはset応答でスタブされます。彼らは特別なことは何もせず、あなたはすでにあなたのテストの外でそれのためにスタブされたコードを書いているでしょう。

モック

モックは、テストの一環として、期待に合わせてセットアップする必要があるものです。モックはあらかじめ決められた方法で設定されていないため、テストでそれを実行するコードがあります。期待を設定するコードは何かを実行する前に実行する必要があるため、モックは実行時に決定されます。

モックとスタブの違い

モックで書かれたテストは通常​​、initialize -> set expectations -> exercise -> verifyテストのパターンに従います。事前に作成されたスタブは、initialize -> exercise -> verify

モックとスタブの類似点

両方の目的は、クラスまたは関数のすべての依存関係のテストを排除して、テストが証明しようとしていることにより焦点を絞って簡単にすることです。


876

序文

オブジェクトの定義はいくつかありますが、実際にはありません。一般的な用語はtest doubleです。この用語には、ダミーフェイクスタブモックが含まれます。ます。

参照

マーティン・ファウラーの記事によると:

  • ダミーオブジェクトは渡されますが、実際には使用されません。通常、これらはパラメータリストの入力にのみ使用されます。
  • 偽のオブジェクトは実際には機能する実装を持っていますが、通常はそれらをプロダクションに適さないようにするいくつかのショートカットを取ります(メモリ内データベースが良い例です)。
  • スタブは、テスト中に行われた呼び出しに対する定型の回答を提供します。通常、テスト用にプログラムされたもの以外にはまったく応答しません。スタブは、「送信」されたメッセージを記憶する電子メールゲートウェイスタブや、「送信」されたメッセージの数だけを記録するなど、呼び出しに関する情報を記録する場合もあります。
  • モックとは、ここで話していることです。事前にプログラムされたオブジェクトで、期待される呼び出しの仕様を形成します。

スタイル

モックvsスタブ=行動テストvs状態テスト

原理

テストの原則によると、テストごとに1つだけです。1つのテストに複数のスタブがある場合がありますが、一般的にはモックは1つだけです。

ライフサイクル

スタブを使用してライフサイクルをテストします。

  1. セットアップ-テスト中のオブジェクトとそのスタブのコラボレーターを準備します。
  2. 演習-機能をテストします。
  3. 状態の確認-アサートを使用してオブジェクトの状態を確認します。
  4. 分解-リソースをクリーンアップします。

モックでライフサイクルをテストする:

  1. セットアップデータ-テストするオブジェクトを準備します。
  2. セットアップの期待 -プライマリオブジェクトで使用されているモックの期待を準備します。
  3. 演習-機能をテストします。
  4. 期待を確認する-モックで正しいメソッドが呼び出されていることを確認します。
  5. 状態の確認-アサートを使用してオブジェクトの状態を確認します。
  6. 分解-リソースをクリーンアップします。

概要

モックとスタブの両方のテストで、質問に対する答えが得られます。結果はどうなりますか?

モックを使用したテストは、次の点にも関心があります。


待って、モックも缶詰の答えを返しますか?そうでなければ、なぜ彼らは質問に答えますか?
AturSams

あなたが書いたものから、モックは「スタブ+期待と検証」であることを知ることができます。モックは「テスト中に行われた呼び出しに対して、通常はテスト用にプログラムされたもの以外の何にもまったく応答しない」という定型の回答を提供するためです。そして、ファウラーがスタブの例として示した例は、実際にはスパイの例です!つまり、モックはスタブであり、スパイはスタブです。また、スタブは、いくつかの機能するメソッドを持つオブジェクトです。これは、Mockitoがstub()メソッドを廃止した理由も説明しています。
コロボク

これと受け入れられた答えを混乱させているのは、この「期待の設定」です。それはどういう意味ですか?通常、「メインコード」では、期待する結果を作成します。しかし、どういうわけか期待をモックオブジェクトに入れたように思えますが、それは私には意味がありません。また、入力を使用してモックを簡単に実行し、結果を保存し、後で「期待」を作成して、比較することもできます。あなたは私があまりに抽象的で曖昧だと思う用語を使います。
IceFire

365

スタブは単純な偽のオブジェクトです。テストがスムーズに実行されるようにするだけです。
モックはよりスマートなスタブです。テストがパスすることを確認します。


33
私はこれが最も簡潔で答えにスポットがあると思います。要点:モックIS-Aスタブ。 stackoverflow.com/a/17810004/2288628は、この回答の長いバージョンです。
PoweredByRice 2014年

8
モックはスタブではないと思います。モックはアサートに使用され、データを返すことはありません。スタブはデータを返すために使用され、アサートすることはありません。
dave1010

2
@ dave1010モックは、間違いなくデータを返したり、例外をスローすることさえできます。渡されたパラメータに応じて、そうする必要があります。
Trenton

2
@trenton渡されたデータに基づいてオブジェクトが戻ったりスローしたりする場合、それは偽物であり、モックではありません。スタブはSUTがメッセージを受信する方法をテストし、モックはSUTがメッセージを送信する方法をテストします。2つを混同すると、オブジェクト指向の設計が悪くなる可能性があります。
dave1010 2015

8
これはすばらしいと思います-スタブは質問に対する回答を返します。モックも質問への回答を返します(is-aスタブ)が、質問が尋ねられたことを確認します!!
Leif

238

以下に、それぞれの説明と、それに続く実際のサンプルを示します。

  • ダミー -を満たすための単なる偽の値API

    :テストに影響を与えないコンストラクターで多くの必須パラメーターを必要とするクラスのメソッドをテストする場合は、クラスの新しいインスタンスを作成するためにダミーオブジェクトを作成できます。

  • 偽物 -一部の外部インフラストラクチャに依存している可能性があるクラスのテスト実装を作成します。(単体テストが実際に外部インフラストラクチャと相互作用しないことは良い習慣です。)

    :データベースにアクセスするための偽の実装を作成し、in-memoryコレクションで置き換えます。

  • スタブ -メソッドをオーバーライドして、ハードコードされた値を返しますstate-based

    :テストクラスは、Calculate()完了するまでに5分かかるメソッドに依存します。5分待つのではなく、実際の実装をハードコードされた値を返すスタブに置き換えることができます。ほんの少しの時間しかかかりません。

  • モック - 状態ベースではなく非常に似てStubinteraction-basedます。これはMock、が何らかの値を返すことを期待するのではなく、メソッド呼び出しの特定の順序が行われたと想定することを意味します。

    例:ユーザー登録クラスをテストしています。呼び出した後Save、それは呼び出す必要がありますSendConfirmationEmail

StubsMocksは実際にはのサブタイプでありMock、どちらも実際の実装とテスト実装を入れ替えますが、特定の理由により異なります。


175

ではcodeschool.comのコース、ゾンビのためのRailsのテスト、彼らは用語のこの定義を与えます:

スタブ

メソッドを指定された結果を返すコードに置き換えるため。

モック

メソッドが呼び出されることを表明するスタブ。

したがって、Sean Copenhaverが彼の回答で述べたように、違いはモックが期待を設定する(つまり、アサーションを作成するか、呼び出されるかどうか、またはどのように呼び出されるか)ことです。


ディロンの投稿を補足するために、これについて考えてみましょう。「MakeACake」と呼ばれるクラスがあり、いくつかのライブラリ(牛乳、卵、砂糖、オーブン)を取ります。
aarkerio 2014

139

スタブはテストに失敗しません、モックは失敗します。


2
これは良いことだと思います。リファクタリング後にテストが同じ動作をするかどうかはご存知でしょう。
RodriKing

1
@RodriKing私も同じ気持ちです。Mockの場合と同じように、本番コードに変更があれば、テストコードに対応する変更があります。痛い!スタブを使用すると、動作をテストし続けているように感じられるため、テストコードでマイクロ変更を行う必要はありません。
tucq88

35

この質問についての最も単純で明確な答えは、Roy Osheroveの著書「The Art of Unit Testing(85ページ)」で与えられていると思います。

スタブを扱っていることを伝える最も簡単な方法は、スタブがテストに失敗することは決してないことに気づくことです。テストが使用するアサートは、常にテスト中のクラスに反しています。

一方、テストはモックオブジェクトを使用して、テストが失敗したかどうかを確認します。[...]

ここでも、モックオブジェクトは、テストが失敗したかどうかを確認するために使用するオブジェクトです。

つまり、フェイクに対してアサーションを作成している場合は、フェイクをモックとして使用していることを意味します。フェイクを使用してテストを実行せずにテストを実行している場合は、フェイクをスタブとして使用しています。


2
私はあなたの答えがトップに到達することを望んでいます。これは、このyoutu.be/fAb_OnooCsQ?t=1006を説明するR. Osherove です。
Michael Ekoka

31

上記のすべての説明を読んで、要約してみましょう。

  • スタブ:テストを実行できるようにするダミーのコード。ただし、何が発生してもかまいません。
  • モック:テストの一部として正しく検証されるダミーのコード。
  • Spy:実際のコードへの呼び出しをインターセプトするダミーのコード。これにより、元のオブジェクト全体を置き換えることなく呼び出しを検証できます。

4
いい答えです。モックは、あなたの定義に基づいて、スパイに非常に似ていますが。答えを更新して、さらにいくつかのテストダブルを含めるとよいでしょう。
Rowan Gontier、2018年

私がこの回答を書いたとき、私はスパイについて聞いていませんでした。
O'Rooney

23

Mockは動作をテストするだけで、特定のメソッドが呼び出されることを確認しています。スタブは、特定のオブジェクトのテスト可能なバージョン(それ自体)です。

アップルのやり方とはどういう意味ですか?


19
「Appleのやり方はどういう意味ですか?」Helveticaを使用
kubi 2010

7
Microsoftの方法ではなくAppleの方法で:)
never_had_a_name 2010

2
これは状況に役立ちますか?
NebulaFox 2010

21

デバッグと比較すると:

スタブは、メソッドが正しい値を返すことを確認するようなものです

モックは、実際にメソッド足を踏み入れ、正しい値を返す前に内部がすべて正しいことを確認するようなものです。


20

メンタルモデルの使用で、説明や記事のすべてではなく、これを理解するのに本当に役立ちました。

あなたの子供がテーブルの上にガラス板を持っていて、彼がそれで遊んでいると想像してください。さて、あなたはそれが壊れることを恐れています。代わりに、あなたは彼にプラスチックプレートを与えます。それはモックになります(同じ動作、同じインターフェース、「よりソフトな」実装)。

さて、あなたはプラスチックの代替品を持っていないと言うので、「それをいじり続けると壊れる!」と説明します。これはスタブであり、事前に事前定義された状態を提供しました。

A ダミーは、彼も使用していなかったフォークだろう...とスパイはすでに働いていたことを使用したのと同じ説明を提供するようなものである可能性があります。


19

彼らの最も重要な違いは彼らの意図だと思います。

WHYスタブWHYモックで説明してみましょう

Mac Twitterクライアントのパブリックタイムラインコントローラーのテストコードを書いているとしましょう

ここにテストサンプルコードがあります

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB:twitter APIへのネットワーク接続が非常に遅いため、テストが遅くなります。私はそれがタイムラインを返すことを知っているので、HTTP twitter APIをシミュレートするスタブを作成しました。これにより、私のテストは非常に速く実行され、オフラインでもテストを実行できます。
  • MOCK:UIメソッドはまだ何も書いていないので、UIオブジェクトにどのメソッドを記述する必要があるのか​​わかりません。テストコードを記述して、コントローラーがどのようにuiオブジェクトと連携するかを知りたいと思います。

モックを書くことで、期待が満たされていることを確認することでオブジェクトのコラボレーション関係を発見しますが、スタブはオブジェクトの動作をシミュレートするだけです。

モックについてもっと知りたい場合は、この記事を読むことをお勧めします:http : //jmock.org/oopsla2004.pdf


1
あなたは正しい考えを持っていると思いますが、ディロン・カーンズはそれをより明確に説明しました。
O'Rooney 2014年

19

非常に明確で実用的なこと:

スタブ:偽造されるクラス/オブジェクトのメソッドを実装し、常に必要なものを返すクラスまたはオブジェクト。

JavaScriptの例:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

モック:スタブと同じですが、メソッドが呼び出されたときに「検証」するロジックが追加されるため、実装がそのメソッドを呼び出していることを確認できます。

@mLevanが言うように、例としてユーザー登録クラスをテストしていると想像してください。Saveを呼び出した後、SendConfirmationEmailを呼び出す必要があります。

非常に愚かなコードの例:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

このスライドは、主な違いを非常によく説明しています。

enter image description here

*ワシントン大学CSE 403 Lecture 16から(「Marty Stepp」によって作成されたスライド)


これは、2つのIMOの違いのより明確な説明です。スタブの場合:テスターはスタブを取得して、テスト中のクラス内で直接使用します。しかしMockの場合、テスターはMockオブジェクトがどのように使用されるかを工夫する必要があります。場合によっては、動作が異なります。対照的に、スタブは異なる動作をすることは期待されていませんが、そのまま使用されます(つまり、いつでも同じデータが返されます)
Dexter

12

Roy Osheroveが出した説明[ビデオリンク]が好きです。

作成されたすべてのクラスまたはオブジェクトは偽物です。それに対して呼び出しを確認する場合、それはモックです。それ以外の場合はスタブです。


12
  • スタブとモック
    • スタブ
      1. メソッド呼び出しに対する具体的な回答を提供する
        • 例:myStubbedService.getValues()は、テスト中のコードに必要な文字列を返すだけです
      2. テスト中のコードがそれを分離するために使用
      3. テストを失敗させることはできません
        • 例:myStubbedService.getValues()はスタブされた値を返すだけです
      4. 抽象メソッドを実装することが多い
    • モック
      1. スタブの「スーパーセット」。特定のメソッドが呼び出されたと断言できる
        • 例:myMockedService.getValues()が1回だけ呼び出されることを確認します
      2. テスト中のコードの動作をテストするために使用されます
      3. テストに失敗する可能性があります
        • 例:myMockedService.getValues()が1回呼び出されたことを確認します。テストされたコードによってmyMockedService.getValues()が呼び出されなかったため、検証は失敗します
      4. インターフェースをモックすることが多い

11

ダブルテストを見てみましょう:

  • フェイクフェイクは、実装が機能しているオブジェクトですが、本番の実装とは異なります。:データアクセスオブジェクトまたはリポジトリのインメモリ実装。
  • スタブ:スタブは、事前定義されたデータを保持し、テスト中に呼び出しに応答するためにそれを使用するオブジェクトです。など:メソッド呼び出しに応答するためにデータベースからデータを取得する必要があるオブジェクト。

  • モック:モックは、受け取った呼び出しを登録するオブジェクトです。テストアサーションでは、予想されるすべてのアクションが実行されたことをモックで確認できます。など:メール送信サービスを呼び出す機能。詳細については、これを確認してください。


1
私の意見では最良の回答
Ero Stefano

9

フェイク本物の物体のように、彼らは両方見ているので、スタブやモックオブジェクト(手書きまたはその他)のいずれかを記述するために使用することができる一般的な用語です。

フェイクがスタブであるかモックであるかは、現在のテストでの使用方法によって異なります。インタラクションのチェック(アサート)に使用される場合、それはモックオブジェクトです。それ以外の場合は、スタブです。

偽物はテストがスムーズに実行されることを確認します。これは、将来のテストの読者が、ソースコードを読み取る必要なく(外部リソースに依存する必要なく)、偽のオブジェクトの動作を理解することを意味します。

テストランとはどういう意味ですか?
以下のコードの例:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

あなたは、テストしたいmailService.SendEMail()ちょうどその結果をシミュレートするために、偽のスタブerrorServiceクラスを作成する必要があるので、その後、テストコードをテストすることができるようになります、あなたは試験方法で例外をシミュレートする必要があることを行うには、メソッドをmailService.SendEMail()メソッド。ご覧のとおり、別のExternal Dependency ErrorServiceクラスからの結果をシミュレートする必要があります。


8

jMockの開発者による紙ではなく、オブジェクトはなくMock Rolesから:

スタブは、あらかじめ用意された結果を返すプロダクションコードのダミー実装です。モックオブジェクトはスタブとして機能しますが、ターゲットオブジェクトとその隣接オブジェクトとの相互作用を計測するアサーションも含まれます。

したがって、主な違いは次のとおりです。

  • スタブに設定された期待値は通常は一般的ですが、モックに設定された期待値はより「賢い」場合があります(たとえば、最初の呼び出しでこれを返し、2番目の呼び出しでこれを返すなど)。
  • スタブは主にSUTの間接入力セットアップするために使用され、モックはSUTの間接入力と間接出力の両方をテストするために使用できます。

要約すると、Fowlerの記事のタイトルから混乱を分散させようとしていますが、モックはスタブですが、スタブだけではありません


1
私はあなたが正しいと思いますが、これがFowlerの記事が紛らわしい理由です。記事のタイトルは「Mocks Are n't Stubs」です...しかし、彼らはそうですか?!_(ツ)_ /¯
stonedauwg

@stonedauwg、確かに、私はあなたの駄洒落と明確化を組み込むために私の投稿を編集しました。これがもう少し役立つことを願っています。
Dimos

@stonedauwg、モックはスタブではなく、長方形が正方形ではないようです。:)
seanriordan08

7

私はThe Art of Unit Testingを読んでいて、次の定義に出くわしました。

偽物は本物の物体のように、彼らは両方見ているので、スタブやモックオブジェクト(手書きまたはその他)のいずれかを記述するために使用することができる一般的な用語です。フェイクがスタブであるかモックであるかは、現在のテストでの使用方法によって異なります。インタラクションのチェック(アサート)に使用される場合は、モックオブジェクトです。それ以外の場合は、スタブです。


5

UncleBob The Little Mockerによるこの興味深い記事に出会いました。すべての用語を非常に理解しやすい方法で説明しているため、初心者には役立ちます。マーティン・ファウラーズの記事は、特に私のような初心者には読みにくいです。


4

スタブはテストの実行に役立ちます。どうやって?テストの実行に役立つ値を提供します。これらの値自体は実際のものではなく、テストを実行するためだけに作成したものです。たとえば、HashMapを作成して、データベーステーブルの値と同様の値を取得します。したがって、データベースと直接対話する代わりに、ハッシュマップと対話します。

モックはテストを実行する偽のオブジェクトです。アサートする場所。


「データベースと直接やり取りする代わりに、ハッシュマップとやり取りします。」...データベースモジュールをコーディングする時間がないため、スタブを使用せずにテストコードを実行できなかったためです。そうでなければ、まったく同じHasmapはモックになります!正しい?
BorisDäppen15年

4

C#とMoqフレームワークを使用したモックとスタブの例を以下に示します。Moqにはスタブ用の特別なキーワードはありませんが、Mockオブジェクトを使用してスタブを作成することもできます。

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

スタブおよびモックテストの観点:

  • スタブ静的な方法でユーザーによって行われたダミー実装です。つまり、スタブは実装コードを記述します。そのため、サービス定義や動的条件を処理できません。通常、これはモックフレームワークを使用せずにJUnitフレームワークで行われます。

  • Mockもダミー実装ですが、その実装はMockitoのようなMockingフレームワークを使用して動的に行われます。したがって、条件とサービス定義を動的な方法で処理できます。つまり、実行時にコードからモックを動的に作成できます。したがって、モックを使用して、スタブを動的に実装できます。


3

プラス便利な回答、サブよりモックを使用する最も強力なポイントの 1つ

(メインコードが依存する)コラボレーターが私たちの制御下にない場合(たとえば、サードパーティのライブラリから)、
この場合、スタブはmockよりも書くのが困難です。


2

私は違いを説明するために私の答えでpythonの例を使用しました。

スタブ -スタブは、開発ライフサイクルの初期にクラスのメソッドを実装するために使用されるソフトウェア開発手法です。それらは一般に、既知のインターフェースの実装のプレースホルダーとして使用されます。インターフェースは確定または既知ですが、実装はまだ不明または確定されていません。スタブから始めます。これは、関数の定義を書き留め、後で使用するために実際のコードを残すことを意味します。利点は、メソッドを忘れることがなく、コードで確認しながらデザインについて引き続き検討できることです。スタブに静的な応答を返させて、コードの他の部分ですぐに応答を使用できるようにすることもできます。スタブオブジェクトは有効な応答を提供しますが、どの入力を渡しても静的であり、常に同じ応答を取得します。

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

モックオブジェクトは、モックテストケースで使用され、それらのオブジェクトで特定のメソッドが呼び出されることを検証します。モックオブジェクトは、制御された方法で実際のオブジェクトの動作を模倣するシミュレーションオブジェクトです。通常、モックオブジェクトを作成して、他のオブジェクトの動作をテストします。モックを使用すると、ユニットテストでは使用できないか扱いにくいリソースをシミュレートできます。

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

これは、rmを実行し、それが呼び出されたパラメーターをアサートする非常に基本的な例です。ここに示すように、関数だけでなくオブジェクトでもモックを使用できます。また、モックオブジェクトを使用してテスト用のスタブを置き換えることができるように、値を返すこともできます。

unittest.mockの詳細、python 2.xのメモモックはunittestに含まれていませんが、pip(pip install mock)を介してダウンロードできるダウンロード可能なモジュールです。

Roy Osheroveの「The Art of Unit Testing」も読んだことがありますが、同様の本がPythonとPythonの例を使用して書かれていれば素晴らしいと思います。誰かがそのような本を知っているなら、共有してください。乾杯:)


2

スタブは、テスト目的で作成された偽のオブジェクトです。モックは、予想される呼び出しが効果的に行われたかどうかを記録するスタブです。


2

スタブは空の関数で、テスト中に未処理の例外を回避するために使用されます。

function foo(){}

モックは、テスト中にOS、環境、またはハードウェアの依存関係を回避するために使用される人工的な機能です。

function foo(bar){ window = this; return window.toString(bar); }

アサーションと状態に関して:

  • イベントまたは状態が変化する前にモックがアサートされます
  • スタブはアサートされず、無関係なユニットからのコードの実行を回避するためにイベント前の状態を提供します
  • スパイはスタブのように設定され、イベントまたは状態変更後にアサートされます
  • 偽物はアサートされず、状態を回避するためにハードコードされた依存関係があるイベントの後に実行されます

参考文献


2
用語集にスパイを追加するための+1。また、「スパイはモックのように設定されている」ではなく、「スパイはスタブのように設定されている」という意味だと思います
Sameh Deabes


2

モックは技術的で機能的なオブジェクトです。

モックはテクニカルです。バイトコード生成のおかげで、これは実際にモックライブラリ(EasyMock、JMockit、および最近ではMockitoがこれらで知られています)によって作成されています
モック実装は、メソッドが呼び出されたときに特定の値を返すようにインストゥルメントできる方法で生成されますが、モックメソッドがいくつかの特定のパラメーター(厳密なチェック)またはパラメーター(厳密なチェックはありません)。

モックのインスタンス化:

@Mock Foo fooMock

行動の記録:

when(fooMock.hello()).thenReturn("hello you!");

呼び出しの確認:

verify(fooMock).hello()

これらは明らかに、Fooクラス/動作をインスタンス化/オーバーライドする自然な方法ではありません。そのため、技術的な側面について言及します。

ただし、モックは SUTから分離する必要があるクラスのインスタンスであるため、モックも機能します。そして、その動作を記録しておけば、スタブの場合と同じようにSUTで使用できます。


スタブは単なる機能オブジェクトです。これは、SUTから分離する必要があるクラスのインスタンスであり、それだけです。つまり、ユニットテスト中に必要なスタブクラスとすべての動作フィクスチャの両方を明示的に定義する必要があります。
たとえば、スタブhello()を作成するには、Fooクラスをサブクラス化する(またはクラスのインターフェースを実装する)必要があり、オーバーライドする必要がありますhello()

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

別のテストシナリオで別の値を返す必要がある場合は、おそらくreturnを設定する一般的な方法を定義する必要があります。

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

その他のシナリオ:副作用メソッド(戻り値なし)があり、そのメソッドが呼び出されたことを確認する場合、スタブクラスにブール値またはカウンターを追加して、メソッドが呼び出された回数をカウントする必要があります。


結論

多くの場合、スタブは単体テスト用に書き込むために多くのオーバーヘッド/コードを必要とします。箱から出してすぐに録音/検証機能を提供することのおかげで、モックが妨げるもの。
そのため、今日では、優れたモックライブラリの登場により、実際にはスタブアプローチが使用されることはほとんどありません。


Martin Fowlerの記事について:モックを使用している間は「モック奏者」のプログラマーだとは思わず、スタブを避けます。
しかし、本当に必要な場合(依存性がわずらわしい場合)にモックを使用し、モックがオーバーヘッドになる依存性を持つクラスをテストする場合は、テストスライスとミニ統合テストを優先します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.