web-dev-qa-db-ja.com

Mockito:「thenReturn」のメソッドを使用してモックを返すと機能しない

Mockitoのバグと思われるものに遭遇しましたが、このテストが機能しない理由について他の誰かが解明できるかどうか疑問に思っていました。

基本的に、次のような2つのオブジェクトがあります。

public class FirstObject {
    private SecondObject secondObject;
    public SecondObject getSecondObject() { return secondObject; }
}

public class SecondObject {
    private String name;
    public String getName() { return name; }
}

最初のオブジェクトはアノテーションとbeforeメソッドを介してモックされます:

@Mock
FirstObject mockedFirstObject;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}

2番目のオブジェクトはメソッドでモックされています。

public SecondObject setupMockedSecondObject() {
    SecondObject secondObject = Mockito.mock(SecondObject.class);
    Mockito.when(secondObject.getName()).thenReturn("MockObject");
    return secondObject;
}

thenReturnに2番目のオブジェクトのモックをセットアップおよび取得するためのこのメソッドの直接呼び出しが含まれている場合、失敗します。

@Test
public void notWorkingTest() {
    Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(setupMockedSecondObject());
    Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}

ただし、同じメソッドによって返されたモックがthenReturnで使用されるローカル変数に割り当てられると、機能します。

@Test
public void workingTest() {
    SecondObject mockedSecondObject = setupMockedSecondObject();
    Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(mockedSecondObject);
    Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}

私たちは何か間違ったことをしているのですか、これは実際にMockitoのバグ/制限ですか?これが機能しない意図的な理由はありますか?

30
LawrenceWeetman

これは確かにMockitoの制限であり、参照されています FAQで

thenReturn()をインラインmock()にできますか?

残念ながら、これを行うことはできません。

when(m.foo()).thenReturn(mock(Foo.class));
//                         ^

その理由は、上記の構成を許可すると、未完成のスタブの検出が機能しないためです。フレームワーク検証の「トレードオフ」と見なします(以前のFAQエントリ)も参照してください。ただし、動作させるためにコードをわずかに変更できます。

//extract local variable and start smiling:
Foo foo = mock(Foo.class);
when(m.foo()).thenReturn(foo);

前述したように、回避策は、目的の戻り値をローカル変数に保存することです。

私が理解しているのは、Mockitoがメソッドを呼び出すたびに、Mockitoがその使用を検証することです。進行中のスタブプロセス中に別のメソッドが呼び出されると、検証プロセスが中断されます。

37
Tunaki