マーティン・ファウラーのモックはスタブではないなど、テストでのモックとスタブに関するさまざまな記事を読みましたが、それでも違いはわかりません。
40 に答える
序文
オブジェクトにはいくつかの定義がありますが、実際にはそうではありません。一般的な用語はテストダブルです。この用語には、ダミー、フェイク、スタブ、モックが含まれます。
参照
マーティンファウラーの記事によると:
- ダミーオブジェクトは渡されますが、実際に使用されることはありません。通常、これらはパラメータリストを埋めるために使用されます。
- 偽のオブジェクトには実際に機能する実装がありますが、通常はショートカットを使用するため、本番環境には適していません(インメモリデータベースが良い例です)。
- スタブは、テスト中に行われた呼び出しに対して定型の応答を提供しますが、通常、テスト用にプログラムされたもの以外にはまったく応答しません。スタブは、「送信した」メッセージを記憶する電子メールゲートウェイスタブや、「送信した」メッセージの数だけなど、通話に関する情報を記録する場合もあります。
- ここで話しているのはモックです。オブジェクトは、受信することが期待される呼び出しの仕様を形成する期待値で事前にプログラムされています。
スタイル
モックvsスタブ=動作テストvs状態テスト
原理
テストの原則によれば、テストごとに1つのものだけがあり、1つのテストに複数のスタブが存在する場合がありますが、通常、モックは1つだけです。
ライフサイクル
スタブを使用してライフサイクルをテストします。
- セットアップ-テスト中のオブジェクトとそのスタブコラボレーターを準備します。
- 演習-機能をテストします。
- 状態の確認-assertsを使用してオブジェクトの状態を確認します。
- 分解-リソースをクリーンアップします。
モックでライフサイクルをテストします。
- セットアップデータ-テスト中のオブジェクトを準備します。
- 期待値の設定-プライマリオブジェクトによって使用されているモックで期待値を準備します。
- 演習-機能をテストします。
- 期待を確認する-モックで正しいメソッドが呼び出されたことを確認します。
- 状態の確認-assertsを使用してオブジェクトの状態を確認します。
- 分解-リソースをクリーンアップします。
概要
モックとスタブの両方のテストで、次の質問に対する答えが得られます。結果はどうなりますか?
モックを使用したテストにも関心があります。結果はどのように達成されましたか。
スタブ
最大の違いは、事前に定義された動作で既に作成したスタブであると思います。したがって、テスト目的で偽造している依存関係(抽象クラスまたはインターフェイスである可能性が最も高い)を実装するクラスがあり、メソッドは設定された応答でスタブアウトされます。彼らは特別なことは何もしませんし、あなたはあなたのテストの外でそれのためのスタブされたコードをすでに書いているでしょう。
モック
モックとは、テストの一環として、期待どおりにセットアップする必要があるものです。モックは事前に定義された方法でセットアップされていないため、テストでそれを実行するコードがあります。期待値を設定するコードは何かを実行する前に実行する必要があるため、ある意味でモックは実行時に決定されます。
モックとスタブの違い
モックで書かれたテストは通常、initialize -> set expectations -> exercise -> verify
テストのパターンに従います。事前に作成されたスタブは。の後に続きますinitialize -> exercise -> verify
。
モックとスタブの類似性
両方の目的は、クラスまたは関数のすべての依存関係のテストを排除することです。これにより、テストは、証明しようとしていることに焦点を絞って簡単になります。
スタブは単純な偽のオブジェクトです。テストがスムーズに実行されることを確認するだけです。
モックはよりスマートなスタブです。テストが通過することを確認します。
それぞれの説明に続いて、実際のサンプルを示します。
ダミー-を満足させるための偽の値
API
。例:コンストラクターでテストに影響を与えない多くの必須パラメーターを必要とするクラスのメソッドをテストしている場合、クラスの新しいインスタンスを作成する目的でダミーオブジェクトを作成できます。
偽物-一部の外部インフラストラクチャに依存している可能性のあるクラスのテスト実装を作成します。(単体テストが実際に外部インフラストラクチャと相互作用しないことをお勧めします。)
例
in-memory
:データベースにアクセスするための偽の実装を作成し、それをコレクションに置き換えます。スタブ-メソッドをオーバーライドして、ハードコードされた値を返します。これは、とも呼ばれ
state-based
ます。例:テストクラスは、
Calculate()
完了するのに5分かかるメソッドに依存します。5分間待つのではなく、実際の実装をハードコードされた値を返すスタブに置き換えることができます。ほんのわずかな時間しかかかりません。モック-状態ベースではなく、非常に似て
Stub
います。interaction-based
これは、から何らかの値を返すことを期待せずMock
、メソッド呼び出しの特定の順序が行われると想定することを意味します。例:ユーザー登録クラスをテストしています。を呼び出した後
Save
、を呼び出す必要がありますSendConfirmationEmail
。
Stubs
とMocks
は実際にはのサブタイプでありMock
、どちらも実際の実装をテスト実装と交換しますが、特定の理由が異なります。
codeschool.comのコースであるRailsTestingfor Zombiesでは、次の用語の定義を示しています。
スタブ
メソッドを、指定された結果を返すコードに置き換えるため。
モック
メソッドが呼び出されるというアサーションを持つスタブ。
したがって、Sean Copenhaverが彼の回答で説明したように、違いは、モックが期待を設定することです(つまり、呼び出されるかどうか、またはどのように呼び出されるかについて主張します)。
スタブはテストに失敗しません、モックは失敗します。
上記のすべての説明を読んで、凝縮してみましょう。
- スタブ:テストを実行できるようにするダミーのコードですが、何が起こってもかまいません。
- モック:テストの一部としてVERIFYが正しく呼び出されるダミーのコード。
- スパイ:実際のコードへの呼び出しをインターセプトするダミーのコードで、元のオブジェクト全体を置き換えることなく呼び出しを検証できます。
この質問についての最も単純で明確な答えは、ロイ・オシェロフの著書「ユニットテストの芸術」(85ページ)から与えられていると思います。
スタブを扱っていることを確認する最も簡単な方法は、スタブがテストに失敗することは決してないことに注意することです。テストで使用されるアサートは、常にテスト対象のクラスに対して行われます。
一方、テストではモックオブジェクトを使用して、テストが失敗したかどうかを確認します。[...]
繰り返しますが、モックオブジェクトは、テストが失敗したかどうかを確認するために使用するオブジェクトです。
スタブとモックはどちらも偽物です。
偽物に対してアサーションを作成している場合は、偽物をモックとして使用していることを意味します。偽物を使用して、アサーションなしでテストを実行する場合は、偽物をスタブとして使用しています。
モックは動作をテストしているだけで、特定のメソッドが呼び出されていることを確認しています。スタブは、特定のオブジェクトのテスト可能なバージョン(それ自体)です。
Appleのやり方とはどういう意味ですか?
メンタルモデルを使用することで、すべての説明や記事ではなく、これを理解するのに本当に役立ちました。
あなたの子供がテーブルの上にガラス板を持っていて、彼がそれで遊んでいると想像してください。今、あなたはそれが壊れるのを恐れています。だから、代わりに彼にプラスチックの皿を渡します。それはモックになります(同じ動作、同じインターフェース、「よりソフトな」実装)。
さて、あなたはプラスチックの代替品を持っていないと言うので、あなたは「それで遊んでいれば、それは壊れます!」と説明します。これはスタブです。事前に事前定義された状態を指定しました。
ダミーは彼が使用しなかったフォークであるでしょう...そしてスパイはあなたがすでに使用したのと同じ説明を提供するようなものである可能性があります。
デバッグと比較すると、次のようになります。
スタブは、メソッドが正しい値を返すことを確認するようなものです
モックは、実際にメソッドにステップインし、正しい値を返す前に内部のすべてが正しいことを確認するようなものです。
非常に明確で実用的であるために:
スタブ:偽造されるクラス/オブジェクトのメソッドを実装し、常に必要なものを返すクラスまたはオブジェクト。
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!');
}
}
テストダブルを見てみましょう:
- 偽物:偽物は、機能する実装を持つオブジェクトですが、本番環境のものと同じではありません。例:データアクセスオブジェクトまたはリポジトリのメモリ内実装。
スタブ:スタブは、事前定義されたデータを保持し、それを使用してテスト中に通話に応答するオブジェクトです。例:メソッド呼び出しに応答するためにデータベースからデータを取得する必要があるオブジェクト。
モック:モックは、受信した呼び出しを登録するオブジェクトです。テストアサーションでは、予想されるすべてのアクションが実行されたことをモックで確認できます。例:電子メール送信サービスを呼び出す機能。詳細については、これを確認してください。
それらの最も重要な違いは彼らの意図だと思います。
なぜスタブとなぜモックで説明しようか
MacTwitterクライアントのパブリックタイムラインコントローラーのテストコードを書いているとします。
これがテストサンプルコードです
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
- スタブ:Twitter APIへのネットワーク接続が非常に遅いため、テストが遅くなります。タイムラインが返されることがわかっているので、HTTP twitter APIをシミュレートするスタブを作成しました。これにより、テストで非常に高速に実行され、オフラインでもテストを実行できます。
- モック:UIメソッドはまだ作成していません。また、UIオブジェクトにどのメソッドを作成する必要があるのかわかりません。テストコードを記述して、コントローラーがUIオブジェクトとどのように連携するかを知りたいと思います。
モックを作成することで、期待値が満たされていることを確認することでオブジェクトのコラボレーション関係を発見できますが、スタブはオブジェクトの動作のみをシミュレートします。
モックについてもっと知りたい場合は、この記事を読むことをお勧めします:http: //jmock.org/oopsla2004.pdf
ロイ・オシェロベの説明が好きです[ビデオリンク]。
作成されたすべてのクラスまたはオブジェクトは偽物です。それに対して呼び出しを確認する場合、それはモックです。それ以外の場合はスタブです。
- スタブとモック
- スタブ
- メソッド呼び出しに具体的な回答を提供する
- 例:myStubbedService.getValues()は、テスト対象のコードに必要な文字列を返すだけです
- テスト対象のコードがそれを分離するために使用する
- テストに失敗することはできません
- 例:myStubbedService.getValues()はスタブ値を返すだけです
- 多くの場合、抽象メソッドを実装します
- メソッド呼び出しに具体的な回答を提供する
- モック
- スタブの「スーパーセット」。特定のメソッドが呼び出されたことを表明できます
- 例:myMockedService.getValues()が1回だけ呼び出されることを確認します
- テスト対象のコードの動作をテストするために使用されます
- テストに失敗する可能性があります
- 例:myMockedService.getValues()が1回呼び出されたことを確認します。myMockedService.getValues()がテストされたコードによって呼び出されなかったため、検証は失敗します
- 多くの場合、インターフェースをモックします
- スタブの「スーパーセット」。特定のメソッドが呼び出されたことを表明できます
- スタブ
私はTheArtof Unit Testingを読んでいて、次の定義に出くわしました。
偽物は、スタブまたはモックオブジェクト(手書きまたはその他)のいずれかを表すために使用できる一般的な用語です。どちらも実際のオブジェクトのように見えるためです。偽物がスタブであるかモックであるかは、現在のテストでどのように使用されているかによって異なります。インタラクションをチェックするために使用される場合(に対してアサートされる)、それはモックオブジェクトです。それ以外の場合は、スタブです。
偽物は、スタブまたはモックオブジェクト(手書きまたはその他)のいずれかを表すために使用できる一般的な用語です。どちらも実際のオブジェクトのように見えるためです。
偽物がスタブであるかモックであるかは、現在のテストでどのように使用されているかによって異なります。インタラクション(に対してアサート)をチェックするために使用される場合、それはモックオブジェクトです。それ以外の場合は、スタブです。
偽物は、テストがスムーズに実行されることを確認します。これは、将来のテストの読者が、ソースコードを読み取る必要なしに(外部リソースに依存する必要なしに)、偽のオブジェクトの動作がどうなるかを理解することを意味します。
テストのスムーズな実行とはどういう意味ですか?
たとえば、以下のコードでは次のようになります。
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()メソッドをテストする場合は、テストメソッドで例外をシミュレートする必要があるため、その結果をシミュレートするためにFake Stub errorServiceクラスを作成するだけで、テストコードでテストできるようになります。 mailService.SendEMail()メソッド。ご覧のとおり、別の外部依存関係ErrorServiceクラスからの結果をシミュレートする必要があります。
スタブ
スタブは、事前にプログラムされた動作を持つメソッドを偽造するために使用されるオブジェクトです。不要な副作用を回避するために、既存のメソッドの代わりにこれを使用することをお勧めします(たとえば、スタブは、サーバーに実際に要求を行わずに、事前にプログラムされた応答を返す偽のフェッチ呼び出しを行う可能性があります)。
モック
モックは、事前にプログラムされた動作と事前にプログラムされた期待を持つメソッドを偽造するために使用されるオブジェクトです。これらの期待が満たされない場合、モックはテストを失敗させます(たとえば、モックは、最初の引数がそうでないことを期待"http://localhost:3008/"
するサーバーに実際に要求することなく、事前にプログラムされた応答を返す偽のフェッチ呼び出しを行う可能性がありますテストは失敗します。)
違い
モックとは異なり、スタブには、テストに失敗する可能性のある事前にプログラムされた期待値がありません。
jMockの開発者による、オブジェクトではなく、モックの役割に関する論文から直接:
スタブは、既定の結果を返す本番コードのダミー実装です。モックオブジェクトはスタブとして機能しますが、ターゲットオブジェクトとその隣接オブジェクトとの相互作用を計測するためのアサーションも含まれます。
したがって、主な違いは次のとおりです。
- スタブに設定された期待値は通常一般的ですが、モックに設定された期待値はより「賢い」場合があります(たとえば、最初の呼び出しでこれを返し、2番目の呼び出しでこれを返すなど)。
- スタブは主にSUTの間接入力を設定するために使用され、モックはSUTの間接入力と間接出力の両方をテストするために使用できます。
要約すると、ファウラーの記事のタイトルから混乱を分散させようとしている間、モックはスタブですが、スタブだけではありません。
彼が使用する一般的な用語はテストダブルです(スタントダブルと考えてください)。テストダブルは、テスト目的で本番オブジェクトを置き換える場合の総称です。Gerardがリストしているdoubleにはさまざまな種類があります。
- ダミーオブジェクトは渡されますが、実際に使用されることはありません。通常、これらはパラメータリストを埋めるために使用されます。
- 偽のオブジェクトには実際に機能する実装がありますが、通常はショートカットを使用するため、本番環境には適していません(InMemoryTestDatabaseが良い例です)。
- スタブは、テスト中に行われた呼び出しに対して定型の応答を提供しますが、通常、テスト用にプログラムされたもの以外にはまったく応答しません。
- スパイはスタブであり、呼び出された方法に基づいていくつかの情報も記録します。これの1つの形式は、送信されたメッセージの数を記録する電子メールサービス(Partial Mockとも呼ばれます)である可能性があります。
- モックは、受信することが期待される呼び出しの仕様を形成する期待値で事前にプログラムされています。予期しない呼び出しを受信した場合は例外をスローでき、検証中に予期したすべての呼び出しを受信したことを確認するためにチェックされます。
UncleBob TheLittleMockerによるこの興味深い記事に出くわしました。すべての用語を非常にわかりやすく説明しているので、初心者にも役立ちます。マーティンファウラーの記事は、特に私のような初心者にとっては読みにくいものです。
そこにはたくさんの有効な答えがありますが、私はこのフォームおじさんボブに言及する価値があると思います: https ://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html
例でこれまでで最高の説明!
モックは技術的オブジェクトであると同時に機能的オブジェクトでもあります。
モックは技術的です。実際、バイトコード生成のおかげで、モックライブラリ(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!";
}
}
別のテストシナリオで別の値の戻り値が必要な場合は、戻り値を設定する一般的な方法を定義する必要があります。
public class HelloStub extends Hello{
public HelloStub(String helloReturn){
this.helloReturn = helloReturn;
}
public String hello {
return helloReturn;
}
}
他のシナリオ:副作用メソッド(戻り値なし)があり、そのメソッドが呼び出されたことを確認する場合は、メソッドが呼び出された回数をカウントするために、スタブクラスにブール値またはカウンターを追加する必要があります。
結論
スタブは、多くの場合、単体テスト用に書き込むために多くのオーバーヘッド/コードを必要とします。箱から出して記録/検証機能を提供することのおかげで、モックが防ぐもの。
そのため、今日では、優れたモックライブラリの出現により、スタブアプローチが実際に使用されることはめったにありません。
Martin Fowlerの記事について:私はモックを使用し、スタブを避けている間は、「モック」プログラマーではないと思います。
しかし、私はそれが本当に必要な場合(依存関係を煩わせる)にモックを使用し、モックがオーバーヘッドになる依存関係を持つクラスをテストする場合は、テストスライシングとミニ統合テストを好みます。
加えて、有用な回答、潜水艦よりもモックを使用することの最も強力なポイントの1つ
[メインコードが依存している]コラボレーターが私たちの管理下にない場合(たとえば、サードパーティのライブラリから)、
この場合、スタブはモックよりも作成が困難です。
スタブは、テストの実行に役立ちます。どのように?テストの実行に役立つ値を提供します。これらの値自体は実際のものではなく、テストを実行するためだけにこれらの値を作成しました。たとえば、HashMapを作成して、データベーステーブルの値に類似した値を提供します。したがって、データベースと直接対話する代わりに、Hashmapと対話します。
モックは、テストを実行する偽のオブジェクトです。ここにassertを置きます。
以下のC#およびMoqフレームワークを使用したモックとスタブの例を参照してください。Moqにはスタブ用の特別なキーワードはありませんが、モックオブジェクトを使用してスタブを作成することもできます。
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";
}
}
}
違いを説明するために、回答に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)を介してダウンロードできるダウンロード可能なモジュールであることに注意してください。
RoyOsheroveによる「TheArtofUnit Testing」も読んだことがありますが、PythonとPythonの例を使用して同様の本が書かれていれば素晴らしいと思います。誰かがそのような本を知っているなら、共有してください。乾杯 :)
スタブは、SUTに値を返すテストダブルです。
モックは、SUTが依存関係を正しく呼び出すことを検証するためにテストが使用するテストダブルです。
また、モックはしばしばスタブです
スタブは空の関数であり、テスト中に未処理の例外を回避するために使用されます。
function foo(){}
モックは、テスト中にOS、環境、またはハードウェアの依存関係を回避するために使用される人工的な機能です。
function foo(bar){ window = this; return window.toString(bar); }
アサーションと状態に関して:
- イベントまたは状態が変化する前にモックがアサートされます
- スタブはアサートされません。無関係なユニットからのコードの実行を回避するために、イベントの前に状態を提供します。
- スパイはスタブのように設定され、イベントまたは状態の変更後にアサートされます
- 偽物はアサートされず、状態を回避するためにハードコードされた依存関係を持つイベントの後に実行されます
参考文献
スタブは、テスト目的で作成された偽のオブジェクトです。モックは、予期された呼び出しが効果的に発生したかどうかを記録するスタブです。
テストするEmployeeServiceという名前のクラスがあり、EmployeeDaoという名前のインターフェイスに1つの依存関係があるとします。
public class EmployeeService{
private EmployeeDao dao;
public EmployeeService(Dao dao){this.dao = dao;}
public String getEmployeeName(int id){
Employee emp = bar.goToDatabaseAndBringTheEmployeeWithId(id);
return emp != null?emp.getFullName:null;
}
//Further state and behavior
}
public interface EmployeeDao{
Employee goToDatabaseAndBringTheEmployeeWithId(int id);
}
テストクラス内:
public class EmployeeServiceTest{
EmployeeService service;
EmployeeDao mockDao = Mockito.mock(EmployeeDao.class);//Line 3
@Before
public void setUp(){
service = new EmployeeService(mockDao);
}
//Tests
//....
}
上記の3行目のテストクラスでは、モックフレームワーク(この場合はMockito)に「ねえ、Mockito、EmployeeDao機能を持つオブジェクトを作成してください」と言います。goToDatabaseAndBringTheEmployeeWithId
フレームワークは、メソッドはあるが実際には本体がないオブジェクトを作成します。そのモックに何をすべきかを指示するのはあなたの仕事です。これはモックです。
ただし、EmployeeDaoインターフェイスを実装するクラスを作成し、代わりにテストクラスで使用することもできます。
public EmployeeDaoStub implements EmployeeDao{
public Employee goToDatabaseAndBringTheEmployeeWithId(int id){
//No trip to DB, just returning a dummy Employee object
return new Employee("John","Woo","123 Lincoln str");
}
}
今回はモックの代わりにスタブを使用してテストクラス内で:
public class EmployeeServiceTest{
EmployeeService service;
EmployeeDao daoStub = new EmployeeDaoStub();//Line 3
@Before
public void setUp(){
service = new EmployeeService(daoStub);
}
//Tests
//....
}
つまり、すべてをまとめると、スタブは、目的の状態にするためだけに依存関係を模倣するために特別に作成する(または他の誰かが作成する)クラスです。はい、他のすべての人が述べているように、それは主に状態に関するものですが、モックは通常、モックフレームワークによって作成され、その内臓がどのように見えるかはわかりません。しかし、スタブを使用すると、取得するクラスがわかります。それは、作成したクラスです。
ところで、依存関係がインターフェイスではなくクラスである場合は、そのクラスを拡張してスタブを作成できます。
スタブはコンポーネントのインターフェイスを実装するオブジェクトですが、呼び出されたときにコンポーネントが返すものを返す代わりに、テストに適した値を返すようにスタブを構成できます。スタブを使用して、単体テストでは、単体がコラボレーターからのさまざまな戻り値を処理できるかどうかをテストできます。単体テストで実際の共同作業者の代わりにスタブを使用すると、次のように表すことができます。
ユニットテスト->スタブ
ユニットテスト->ユニット->スタブ
ユニットテストは、ユニットの結果と状態をアサートします
まず、単体テストでスタブを作成し、その戻り値を構成します。次に、ユニットテストでユニットが作成され、その上にスタブが設定されます。ここで、ユニットテストはユニットを呼び出し、ユニットはスタブを呼び出します。最後に、単体テストは、ユニットに対するメソッド呼び出しの結果についてアサーションを作成します。
モック はスタブのようなものですが、モックで呼び出されたメソッドを判別できるメソッドもあります。したがって、モックを使用すると、ユニットがさまざまな戻り値を正しく処理できるかどうか、およびユニットがコラボレーターを正しく使用しているかどうかの両方をテストできます。たとえば、daoオブジェクトから返された値では、データがステートメントまたはPreparedStatementのどちらを使用してデータベースから読み取られたかを確認することはできません。また、値を返す前にconnection.close()メソッドが呼び出されたかどうかもわかりません。これはモックで可能です。言い換えれば、モックは、ユニットが共同作業者と完全に相互作用することをテストすることを可能にします。ユニットで使用される値を返すコラボレーターメソッドだけではありません。単体テストでモックを使用すると、次のように表すことができます。
ユニットテスト->モック
ユニットテスト->ユニット->モック
ユニットテストは、ユニットの結果と状態をアサートします
ユニットテストは、モックで呼び出されたメソッドをアサートします
詳細>>こちら
被験者は、特定のプロンプト(関数呼び出し)または他の刺激に応答してアクションを実行します。テスト状況の具体例を次に示します。
シナリオ-EMT学生試験
学生は救急医療技術者になるために勉強しました。このテスト状況に慣れていない場合は、恥知らずなシーズン6、エピソード10のIanGallagherをご覧ください。
テスト目的でさまざまな病気の患者を見つけるのは費用がかかりすぎます。代わりに、アクターを使用します。被験者(イアン)に「あなたは現場に到着し、患者は動けなくなり、無意識になります。最初に何をしますか?」と尋ねます。イアンは「シーンが安全かどうかを確認します」と応答します。そして、テストインストラクターは「シーンは安全だ」と言います。
インストラクター(およびアクター)は、被験者の質問に任意の回答を挿入することができます。
ここでは、インストラクター(および俳優)はモックです。医学教育では、コンピューター科学者と同じようにこの用語(モックコードシミュレーションなど)を使用します。
シナリオ-Webサイトに登録する
あなたは、聞いた新しいメールサービスであるYahooをテストしています。サインアップするには、誕生日とその他の煩わしい質問への回答を提供する必要があります。
このウェブサイトでは、21歳以上である必要があります。したがって、1970年1月1日の値を入力します。これは要件を満たし、誕生日を覚えて入力するワークフローを実装するという面倒なプロセスから解放されます。
この日付はスタブです。この単語の使用法は、コンピュータサイエンスに固有のものです。
スタブとモックの両方が外部依存関係をオーバーライドしますが、違いは
スタブ->データをテストするには
モック->動作をテストするには
偽物/ダミー->何もテストしません(空のメソッドで機能をオーバーライドするだけです。たとえば、Logger
テスト中のロギングノイズを回避するために置換します)
以下は私の理解です...
テストオブジェクトをローカルで作成し、それをローカルサービスに提供する場合は、モックオブジェクトを使用しています。これにより、ローカルサービスに実装したメソッドのテストが行われます。動作を検証するために使用されます
実際のサービスプロバイダーからテストデータを取得する場合、インターフェイスのテストバージョンからオブジェクトのテストバージョンを取得する場合でも、スタブを操作している場合、スタブは特定の入力を受け入れ、対応する出力を提供して実行に役立てることができます。状態検証..。
スタブは、テストで設定した期待収益値を持つメソッドで使用されます。モックは、呼び出されたことをアサートで検証されるvoidメソッドで使用されます。
モック-モックは、メソッドまたは関数(またはモッククラスの場合のようにメソッドと関数のグループ)への呼び出しをインターセプトします。これは、そのメソッドまたは関数に代わるものではありません。その傍受では、モックは、入力と出力の記録、呼び出しの短絡の決定、戻り値の変更など、必要なことをすべて実行できます。
スタブ-スタブは、メソッドまたは関数(またはスタブクラスの場合のようにメソッドと関数のグループ)の有効な完全に機能する実装であり、メソッド、関数、またはメソッドと関数のグループと同一のインターフェイス/署名を持ちます。のためのスタブです。スタブ化された実装は、通常、単体テストのコンテキスト内で許容できることのみを実行します。つまり、スタブ化されているものの動作を模倣しながら、たとえばIOは実行しません。