Mock和Spy的区别

简答

mock方法和spy方法都可以对对象进行mock。但是前者是接管了对象的全部方法,而后者只是将有桩实现(stubbing)的调用进行mock,其余方法仍然是实际调用。

spy实现示例

1
2
3
4
5
6
7
8
9
List<String> list = new LinkedList<String>();  
List<String> spy = spy(list);
when(spy.size()).thenReturn(100);

spy.add("one");
spy.add("two");

assertEquals(spy.get(0), "one");
assertEquals(100, spy.size());

spy的标准是:如果不打桩,默认执行真实的方法,如果打桩则返回桩实现。

spy是否真的调用了方法?

使用不同的打桩方式,对于spy是否真的调用该方法的影响是不同的。例如:

difference between doReturn and when

  • when(...) thenReturn(...)做了真实调用。只是返回了指定的结果
  • doReturn(...) when(...)不做真实调用

注意:

This behavior just works for spied objects, since are “wrapper” of real objects. In the case of mocked objects, it does not matter if it’s when/thenReturn or doReturn/ when. Mocked objects never calls real methods.
对于mock对象,没有这种区别

另外一种部分Mock的方法——callRealMethod()

即使是mock对象,也可以去调用真实的方法,即使用callRealMethod()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Test  
public void callRealMethodTest() {
Jerry jerry = mock(Jerry.class);

doCallRealMethod().when(jerry).goHome();
doCallRealMethod().when(jerry).doSomeThingB();

jerry.goHome();

verify(jerry).doSomeThingA();
verify(jerry).doSomeThingB();
}

class Jerry {
public void goHome() {
doSomeThingA();
doSomeThingB();
}

// real invoke it.
public void doSomeThingB() {
System.out.println("good day");

}

// auto mock method by mockito
public void doSomeThingA() {
System.out.println("you should not see this message.");

}
}