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


196

我目前正在使用Mockito在Spring MVC应用程序中模拟我的服务层对象,在该应用程序中我想测试我的Controller方法。但是,当我阅读Mockito的细节时,我发现这些方法doReturn(...).when(...)等效于when(...).thenReturn(...)。所以,我的问题是,拥有两种做同一件事的方法有什么意义?doReturn(...).when(...)和之间的细微差别是when(...).thenReturn(...)什么?

任何帮助,将不胜感激。


1
Javadoc在某些情况下doReturn()很有用。
Sotirios Delimanolis 2013年

5
我认为主要区别之一是doReturn(...)。when(..)是较旧的版本,它的类型也不安全,因此当编译器不断抱怨转换时,我们有时可以使用它。在类型安全方面,when(...)。thenReturn(..)要好得多
user2511882 2013年

Answers:


227

存根的两种语法大致相同。但是,您始终可以将其doReturn/when用于存根。但是在某些情况下您不能使用when/thenReturn。废除无效方法就是这样的一种。其他方法包括与Mockito间谍一起使用,并多次重复使用相同的方法。

可以when/thenReturn提供(doReturn/when但没有提供)的一件事是在编译时对返回的值进行类型检查。但是,我相信这几乎没有任何价值-如果您输入的类型有误,则可以在运行测试后立即发现。

我强烈建议仅使用doReturn/when。学习两种语法何时行得通没有意义。

您不妨参考我在Forming Mockito“语法”中的答案-有关一个非常紧密相关的问题的更详细答案。


16
我有点不同意大卫。我经常遇到这样的情况,在使用时我会返回错误的类型,doReturn/when并在接下来的几分钟中花时间找出错误的原因。使用编译类型类型检查变得非常有用when/thenReturn
Saket

11
请记住,Mockito建议您使用use when/thenReturn而不是doReturn/when
CodyEngel

2
@CodyEngel,除了我在这里和stackoverflow.com/q/11462697的答案中概述的内容外,没有任何其他建议的理由。几年前,我与目前担任Mockito首席开发人员的Brice Dutheil讨论了这一点,他深表赞同。我要他在这里发表评论(不保证他会发表评论)。
达伍德·伊本·卡里姆

18
javadoc的规定,doReturn/when是一个权衡。团队不会以一种或另一种方式提出建议,但请注意,该when/then方法更加直观,可读性强,并提供编译时间检查,这是使Mockito变得流行且易于使用的方法,请不要忘记当代码库被共享时。团队中的各种技能; 但是它在间谍和无效方法方面有缺点。
布莱斯

5
仅作记录:doReturn()具有将方法调用转换为YODA样式编码的巨大缺点。事情后来记下来就是。大多数人从左到右阅读;因此,您现在必须不断记住扭转头脑中的“返回时”逻辑。
GhostCat

199

如果您使用间谍对象(标有@Spy)而不是模拟对象(标有),则两种方法的行为会有所不同@Mock

  • when(...) thenReturn(...) 在返回指定值之前进行真正的方法调用。因此,如果被调用的方法引发Exception,则必须对其进行处理/模拟。等等。当然,您仍然会得到结果(在中定义thenReturn(...)

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

例:

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

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

测试:

@Spy
private MyClass myClass;

// ...

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

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");

37
这种行为仅适​​用于间谍对象,因为它们是真实对象的“包装”。对于模拟对象,无论是when / thenReturn还是doReturn / when。模拟对象永远不会调用真实方法。
拉斐尔·奥拉焦2015年

您能否提供更多信息,为什么我们需要使用此功能?我看不到实际的用例。测试的目的是确认不同用例下代码的正确性。如果方法的calll引发异常,则test应该引发异常,而不返回值
Gleichmut

@Gleichmut这是一个假设的场景,其中我展示了doReturn的用法/优点。在实际的应用程序中,只返回一个异常的方法当然是没有道理的..但是您有一些可能在某些情况下会引发异常的方法(可能不像这样那么薄)
。– akcasoy

1
只是为了澄清一下:when()。thenReturn()方法仅调用一次实际方法(间谍的方法,与模拟无关紧要)。这发生在您指定模拟行为的行中(when(myClass.anotherMethodInClass(). thenRet ...)。此后,不再调用实际方法。也许很高兴知道您在阅读说明时是否确实想到了装饰器逻辑以上。
纳斯

这似乎不是的优势doReturn(),它似乎是对库的滥用。进行监视而不是单纯的模拟的目的是利用真实的调用。他们还警告不要像这样使用Spies:github.com/mockito/mockito/wiki/Using-Spies-(and- Fakes)(并建议扩展类并覆盖该方法)
马修(Matthew)阅读

13

在无法使用Mockito.when(Object)的极少数情况下,Mockito Javadoc似乎可以告诉您为什么使用use doReturn()而不是when()Use 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优雅语法的折衷方案。请注意,这种情况非常罕见。间谍活动应该是零星的,并且很少使用异常处理。更不用说总的来说,过度存根是一种潜在的代码气味,它指出了太多的存根。


6

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

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.