2017-12-14 4 views
0

私は、Mockitoのスパイのための方法をスタッフィングするために "Deep Stubs"を使用する方法を見つけることができませんでした。上記のコードは問題なくコンパイルしますが、テストを実行すると、それは(この場合はNameクラス、)戻り値の型ができないことを言って失敗しmockitoのスパイのためのAnswers.RETURNS_DEEP_STUBSに相当。

@Spy private Person person = //retrieve person 

    @Test 
    public void testStubbed() { 
     doReturn("Neil").when(person).getName().getFirstName(); 
     assertEquals("Neil", person.getName().getFirstName()); 
    } 

:私は何を探していることは、このようなものですgetName()によって返されます。

通常、モック時には、模擬対象ごとに
@Mock(answer = Answers.RETURNS_DEEP_STUBS)を使用する必要があります。しかし、スパイのようなものはないようです。

スパイを使用して深いスタブをかけられた疑惑を成功させた人は誰ですか?

私が受けてるエラーを以下にリストされている:

String cannot be returned by getName() 
getName() should return Name 

Due to the nature of the syntax above problem might occur because of: 
1. Multithreaded testing 
//I'm not doing multithreaded testing 
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies with doReturn|Throw() family of methods 
//As shown above, I'm already using the doReturn family of methods. 

答えて

0

私はまだこれを行うには良い方法がありますかどうかを知りたいのですが、私が来て、誰のためのソリューションを投稿したいと思います探している。

以下の解決策は、依存関係の各レベルに対して新しいモック(または実際のオブジェクト/スパイ)を作成する必要があるため、正常に動作します。つまり、スタブを作成するためにメソッド呼び出しを連鎖させる代わりに、各レベルを個別にモックします。

@Spy private Person person = //retrieve person 
@Mock private Name name; 

@Test 
public void testStubbed() { 
    doReturn(name).when(person).getName(); 
    doReturn("Neil").when(name).getName(); 
    assertEquals("Neil", person.getName().getFirstName()); 
} 
+0

'@Mock Name name'から' = new Name() 'を削除する必要があります。とにかくMockitoは初期化時にその値を上書きします。 –

+0

あなたは正しく、更新されました。私がこれを書いたときに変数宣言に多くの注意を払っていなかった。 –

0

あなたはdoAnswer(RETURNS_DEEP_STUBS)を使って欲しい深いスタブに少し近づくことができますが、任意の深さのメソッドは、その親の呼び出しをスタブに注意を取らずに呼び出し、オーバーライドすることはできません。私はあなたの答えでやっているように、手作業のシングルレベルのモックに固執します。あるいは、できるだけ少ないモックを使用してください。


スパイのデフォルトの動作は、通常、実際の(あなたの名前のような)オブジェクトではなくMockitoのスパイを返しますその実際のメソッド呼び出しに委譲することです。つまり、通常、Mockitoを使用してオブジェクトの動作を変更することはできません。スパイは、実際にスパイされるオブジェクトと同じクラスではなく、すべてのフィールド値がスパイからコピーされる生成サブクラスです-on値。 (委任スパイは、メソッド呼び出しやフィールド値を含め、thisに関して非常にunintutitive行動を持ってしまうため、コピーは、重要な機能である。)

Foo foo = new Foo(); 
foo.intValue = 42; 
foo.someObject= new SomeObject(); 

Foo fooSpy = Mockito.spy(foo); 
// Now fooSpy.intValue is 42, fooSpy.someObject refers to the exact same 
// SomeObject instance, and all of fooSpy's non-final methods are overridden to 
// delegate to Mockito's behavior. Importantly, SomeObject is not a spy, and 
// Mockito cannot override its behavior! 

だから、これは動作しません。

doReturn("Neil").when(person).getName().getFirstName(); 
// Mockito thinks this call ^^^^^^^^^ should return "Neil". 

そして、どちらもこのう:少なくともに最も好ましいから

あなたの状況では
doReturn("Neil").when(person.getName()).getFirstName(); 
// The object here ^^^^^^^^^^^^^^^^ won't be a mock, and even if Mockito 
// could automatically make it a mock, it's not clear whether that 
// should be the same spy instance every time or a new one every time. 

、私は順番に、以下を選択したい:

  1. 実際のNameオブジェクトを作成し、doReturnを使用してインストールします。結局のところ、名前はデータオブジェクト(別名値オブジェクト)だと思われます。これは、依存関係、堅実な振る舞い、および模擬しにくい状態遷移を持たない可能性があります。あなたはそれを嘲笑して何かを得ることはできません。

  2. モック名を作成し、as you do in your answerをインストールします。これは、Nameが見た目よりも複雑である場合、または実際に存在しない場合に特に便利です。

    doReturn("Neil").when(person.getName()).getFirstName(); 
    

    あなたがして上書きすることができ

  3. 深いスタブを返すためのgetNameを交換...

    doAnswer(RETURNS_DEEP_STUBS).when(person).getName(); 
    

    ... ... ...でも、任意の深さの値について。最後の編集として

    doReturn("Gaelic").when(person.getName() 
               .getEtymology() 
               .getFirstNameEtymology()) 
        .getOrigin(); 
    

、部分的モックの危険性の一つは、それが現実とどの偽造されている行動伝えるために、それは本当にハードになることです。これは、あなたがテストしている振る舞いが振る舞いであり、模擬振る舞いではないことを保証するのが難しくなる可能性があります。深刻なスタブのもう1つの危険は、定義によってLaw of Demeterに違反している可能性があることです。テストでこの種のテクニックを頻繁に使用していると思われる場合は、テスト中のシステムを再構築することを考慮する必要があります。

関連する問題