Java Mockito:使用“中的方法”;然后返回“;要返回模拟数据';行不通

Java Mockito:使用“中的方法”;然后返回“;要返回模拟数据';行不通,java,unit-testing,mocking,mockito,Java,Unit Testing,Mocking,Mockito,我遇到了Mockito的一个bug,但我想知道是否有其他人可以解释为什么这个测试不起作用 基本上,我有两个对象,如下所示: public class FirstObject { private SecondObject secondObject; public SecondObject getSecondObject() { return secondObject; } } public class SecondObject { private String name;

我遇到了Mockito的一个bug,但我想知道是否有其他人可以解释为什么这个测试不起作用

基本上,我有两个对象,如下所示:

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);
}
在方法中模拟第二个对象:

public SecondObject setupMockedSecondObject() {
    SecondObject secondObject = Mockito.mock(SecondObject.class);
    Mockito.when(secondObject.getName()).thenReturn("MockObject");
    return secondObject;
}
thenReturn
包含对此方法的直接调用以设置并获取第二个对象的模拟时,它将失败:

@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中的一个缺陷/限制?是否有故意不起作用的原因?

这确实是Mockito的一个限制,引用如下:

我可以
thenReturn()
内联
mock()
吗? 不幸的是,您不能这样做:

when(m.foo()).thenReturn(mock(Foo.class));
//                         ^
原因是,如果我们允许上述构造,检测未完成的存根将不起作用。我们认为是框架验证的“折衷”(参见前面的常见问题条目)。但是,您可以稍微更改代码以使其正常工作:

//extract local variable and start smiling:
Foo foo = mock(Foo.class);
when(m.foo()).thenReturn(foo);
如前所述,解决方法是将所需的返回值存储在局部变量中,就像您所做的那样

我的理解是,每次调用Mockito的方法时,它都会验证您对它的使用。在正在进行的存根过程中调用另一个方法时,您正在破坏其验证过程。

@Test
public void testAuthenticate_ValidCredentials()抛出失败的OAuthenticateException{
字符串username=“User1”;
字符串password=“password”;
/*配置返回True的时间…然后返回模拟对象上的配置-Q5*/
//在这里编写代码
assertTrue(authenticator.authenticateUser(用户名、密码));
}

您不能在
然后返回中使用方法,但可以在
然后回答中使用方法
您的代码将在条件发生后被调用,
与基于
thenReturn的任何解决方法不同

因此你可以写:

@Test
public void nowWorkingTest() {
    Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new Answer<Map>() {
        @Override
        public Map answer(InvocationOnMock invocation) {
            return setupMockedSecondObject();
        }
    });
    Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
@测试
公共无效nowWorkingTest(){
Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new-Answer()){
@凌驾
公共映射应答(调用锁调用){
返回setupMockedSecondObject();
}
});
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(),“MockObject”);
}

让我们来看另一个例子

这可能是由于Mockito在
/
然后返回
(或其他)调用时如何实现其
。在调用之前的
然后return
循环时,调用另一个
,你正在打破这个链条。现在你可以了!这是一个旧答案。@HamzehSoboh不,您不能,因为此方法以前运行过,我们希望它按照“then return”的要求在之后执行。这是一个限制,因为在执行返回之前,spied foo()方法无法更新状态。thenReturn参数不能从spied或mocked方法设置的状态中获益。