关于java:Mockito – doReturn()和when()之间的区别

Mockito - difference between doReturn() and when()

我目前正在一个SpringMVC应用程序中使用Mockito模拟我的服务层对象,在这个应用程序中我想测试我的控制器方法。然而,正如我一直在阅读Mockito的细节一样,我发现方法doReturn(...).when(...)等同于when(...).thenReturn(...)。所以,我的问题是,有两种方法做同样的事情有什么意义,或者说,doReturn(...).when(...)when(...).thenReturn(...)之间的细微区别是什么?

任何帮助都将不胜感激。


存根的两个语法大致相等。但是,您可以始终使用doReturn/when作为存根;但在某些情况下,您不能使用when/thenReturn。留茬空隙法就是这样一种。其他包括与mockito-spies一起使用,并多次使用相同的方法。

when/thenReturn给您的一件事,doReturn/when不给您的,是在编译时对您返回的值进行类型检查。然而,我相信这几乎没有价值——如果你把类型弄错了,你一运行测试就会发现。

我强烈建议只使用doReturn/when。学习两种语法是没有意义的。

你可以参考我在形成mockito"语法"时的答案——一个非常密切相关问题的更详细的答案。


如果使用监视对象(用@Spy注释)而不是模拟对象(用@Mock注释),这两种方法的行为会有所不同:

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

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

例子:

1
2
3
4
5
6
7
8
9
public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

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

测试:

1
2
3
4
5
6
7
8
9
10
@Spy
private MyClass myClass;

// ...

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

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


mockito javadoc似乎说明了为什么使用doReturn()而不是when()。在那些您不能使用mockito.when(object)的罕见情况下使用doreturn()。

Beware that Mockito.when(Object) is always recommended for stubbing
because it is argument type-safe and more readable (especially when
stubbing consecutive calls).

Here are those rare occasions when doReturn() comes handy:

1. When spying real objects and calling real methods on a spy brings side
effects

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

//Impossible: real method is called so spy.get(0) throws
IndexOutOfBoundsException (the list is yet empty)

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

//You have to use doReturn() for stubbing:
doReturn("foo").when(spy).get(0);

2. Overriding a previous exception-stubbing:

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

//Impossible: the exception-stubbed foo() method is called so
RuntimeException is thrown. when(mock.foo()).thenReturn("bar");

//You have to use doReturn() for stubbing:

doReturn("bar").when(mock).foo(); Above scenarios shows a tradeoff
of Mockito's elegant syntax. Note that the scenarios are very rare,
though. Spying should be sporadic and overriding exception-stubbing is
very rare. Not to mention that in general overridding stubbing is a
potential code smell that points out too much stubbing.


继续这个答案,还有另一个区别,如果您希望方法返回不同的值,例如,当第一次调用它时,第二次调用它时,那么您可以传递值,例如…

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

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


后一种方法用于返回void的模拟上的方法。

请看一下,例如:如何用mockito使mock to-void方法


"mock"可以模拟对象而不是创建它;"spy"可以使用实际参数创建实际对象。当我们进行单元测试时,我们经常使用它们。但"when(xxx)。thenreturn(xxx)"用于模拟,"doreturn(xxx)"用于间谍。