Mockito - doReturn()和when()之间的区别

bla*_*her 171 java unit-testing mockito

我目前正在使用Mockito来模拟Spring MVC应用程序中的服务层对象,我想在其中测试我的Controller方法.然而,正如我一直在阅读Mockito的具体细节,我发现这些方法doReturn(...).when(...)相当于when(...).thenReturn(...).所以,我的问题是什么是有两个方法,做同样的事情或之间有什么细微的区别点doReturn(...).when(...)when(...).thenReturn(...)

任何帮助,将不胜感激.

Daw*_*ica 204

存根的两种语法大致相同.但是,你总是可以doReturn/when用来存根; 但有些情况下你不能使用when/thenReturn.挖空虚方法就是这样.其他包括与Mockito间谍一起使用,并且不止一次地使用相同的方法.

在编译时,when/thenReturn给你的一件事就是对你doReturn/when要返回的值进行类型检查.但是,我相信这几乎没有任何价值 - 如果你的类型错了,你会在你进行测试后立即发现.

我强烈建议只使用doReturn/when.当一个人学习时,学习两种语法是没有意义的.

您可能希望参考我在Forming Mockito"语法"中的答案 - 对一个非常密切相关的问题的更详细的答案.

  • [javadoc](https://static.javadoc.io/org.mockito/mockito-core/2.7.11/org/mockito/Mockito.html#doReturn(java.lang.Object))声明`doReturn/when `是一种权衡.团队不推荐这种或那种方式,但注意`when/then`方法更直观,更可读并提供编译时间检查,这是使Mockito流行且易于使用的方法,不要忘记当代码库由您团队中的各种技能组共享; 但它有关于间谍和空洞方法的缺点. (17认同)
  • 我有点不同意大卫.我经常遇到使用`doReturn/when`时返回错误类型的情况,并在接下来的几分钟内找出问题所在.使用`when/thenReturn`编译类型检查变得非常有用. (13认同)
  • 请记住,Mockito建议您使用`when/thenReturn`而不是`doReturn/when`. (8认同)
  • 仅作记录:`doReturn()`的最大缺点是将其转换为方法调用的YODA样式编码。事情后来才被写下来。大多数人从左到右阅读;因此,您现在必须不断记住要扭转返回逻辑。 (5认同)
  • @CodyEngel,除了我在此处和http://stackoverflow.com/q/11462697中的答案中概述的内容之外,没有任何其他建议的理由。几年前,我与目前担任Mockito首席开发人员的Brice Dutheil讨论了这一点,他深表赞同。我将请他在此处发表评论(不保证他会发表评论)。 (2认同)
  • “如果你的类型错误,你一运行测试就会发现。” 是的,只要运行时类型检查正确实现即可。https://github.com/mockito/mockito/issues/1155 我知道这是处理异常的检查性,而不是返回类型,这是不同的;但这允许你让你的模拟做不可能的事情。出于对mockito开发人员的应有尊重,我更重视Java编译器的类型检查而不是他们的库,因此更愿意在可能的情况下利用前者。 (2认同)

akc*_*soy 173

如果您使用间谍对象(带注释@Spy)而不是模拟(带注释@Mock),则两种方法的行为都不同:

  • when(...) thenReturn(...) 在返回指定值之前进行实际的方法调用.因此,如果被调用的方法抛出异常,你必须处理它/模拟它等.当然你仍然得到你的结果(你定义的内容thenReturn(...))

  • doReturn(...) when(...) 根本不会调用该方法.

例:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}
Run Code Online (Sandbox Code Playgroud)

测试:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");
Run Code Online (Sandbox Code Playgroud)

  • 此行为仅适用于间谍对象,因为它是真实对象的"包装".对于模拟对象,无论是在/ thenReturn还是doReturn/when时都无关紧要.模拟对象永远不会调用真正的方法. (31认同)
  • 只是为了澄清:when().thenReturn()方法仅调用一次实际方法(间谍的方法 - 对于模拟来说无关紧要)。这发生在您指定模拟行为的行中(when(**myClass.anotherMethodInClass()**.thenRet...)。之后,实际方法永远不会再次被调用。也许很高兴知道您是否确实期望一些装饰器逻辑当阅读上面的解释时。 (3认同)

小智 10

Mockito javadoc似乎告诉为什么 在不能使用Mockito.when(Object)的极少数情况下使用doReturn()when()不是使用doReturn().

请注意,Mockito.when(Object)始终建议用于存根,因为它是参数类型安全且更具可读性(特别是当存根连续调用时).

以下是doReturn()出现的罕见情况:

1.当间谍的真实对象,并呼吁间谍真正的方法带来的副作用

List list = new LinkedList(); List spy = spy(list);

//不可能:调用真正的方法,因此spy.get(0)抛出IndexOutOfBoundsException(列表尚未清空)

when(spy.get(0)).thenReturn("foo");

//你必须使用doReturn()进行存根: doReturn("foo").when(spy).get(0);

2.覆盖先前的异常 - 存根:

when(mock.foo()).thenThrow(new RuntimeException());

//不可能:调用异常存根的foo()方法,因此抛出RuntimeException. when(mock.foo()).thenReturn("bar");

//你必须使用doReturn()进行存根:

doReturn("bar").when(mock).foo(); 以上场景显示了Mockito优雅语法的权衡.请注意,这些场景非常罕见.间谍应该是零星的,而且压倒一切的例外情况非常罕见.更不用说一般来说,覆盖存根是一种潜在的代码气味,指出了过多的存根.


vik*_*eve 5

后一种选择用于返回的模拟方法void

例如,请在此处查看: 如何使用Mockito使模拟方法转换为无效方法


AZ_*_*AZ_ 5

继续这个答案,还有另一个区别,如果您希望您的方法返回不同的值(例如,第一次调用时,第二次调用等等时),则可以传递值,例如...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));
Run Code Online (Sandbox Code Playgroud)

因此,在同一测试用例中调用该方法时,它将返回false,然后再次返回false,最后返回true。