Mockito 详解:第一部分:对象创建
零:前提条件
先明确一个词:存根(或者说是打桩),指的是对某个方法指定返回策略的操作(具体表现为两种:1指定返回值,2使用doCallRealMethod()或者thenCallRealMethod()指定当方法被调用时执行实际代码逻辑),功能就是当测试执行到此方法时直接返回我们指定的返回值(此时不会执行此方法的实际代码逻辑)或者执行此方法的实际代码逻辑并返回。比如:
我们先定义一个对象:
public class Mock {
public String m1() {
throw new RuntimeException();
}
}
然后我们进行下面的操作:
Mock m = Mockito.mock(Mock.class);
//对m1()方法进行存根
Mockito.doReturn("1").when(m).m1();
基于上面的代码我们可以说:我们对m对象的m1()方法进行了存根。
此时我们调用m对象的m1()方法时,可以直接得到返回值"1"而不会执行m1方法的实际代码逻辑:
Assert.assertEquals("1",m.m1());
此时断言为真。
下文示例代码会使用到的对象:
public class Foo {
private Bar bar;
public int sum(int a, int b) {
return bar.add(a, b);
}
}
public class Bar {
public int add(int a, int b) {
return a + b;
}
}
测试中我们创建的对象一般可以分为三种:被测对象、mock对象和spy对象。
首先我们明确一下这三种对象的概念:
- 被测对象:即我们想要测试的对象,比如xxService、xxUtils等。
- mock对象:一般为我们被测对象的依赖对象。典型如被测对象的成员变量。主要是一些测试中我们不关注的对象。我们只想要得到这些对象的方法的返回值。而不关注这些方法的具体执行逻辑。此时我们可以将这些对象创建为mock对象。
- spy对象:在Mockito中它是基于部分mock概念提出的。spy对象也可由mock对象使用特定参数下创建。也就是说:**spy对象其实是一种特殊的mock对象。**和mock对象一样,它可以作为被测对象的依赖对象。此时它和mock对象的最大的区别是mock对象的方法如果没有被存根,调用时会返回相应对象的空值(下文有详细介绍);而spy对象的方法被调用时则会调用真实的代码逻辑。
在基于JUnit测试框架的测试代码书写时,我们有两种方式可以激活Mockito框架对其相关注解(@InjectMocks/@Mock/@Spy)的支持。
-
使用@RunWith(MockitoJUnitRunner.class),如下所示
-
public class Foo { private Bar bar; public int sum(int a, int b) { return bar.add(a, b); } } public class Bar { public int add(int a, int b) { return a + b; } } @RunWith(MockitoJUnitRunner.class) public class MockitoTests { @InjectMocks private Foo foo; @Mock private Bar bar; @Test public void mockTest() { Mockito.when(bar.add(1, 2)).thenReturn(7); int result = foo.sum(1, 2); Assert.assertEquals(7, result); } }
-
-
使用MockitoAnnotations.openMocks(this),如下所示:
-
public class MockitoTests { @InjectMocks private Foo foo; @Mock private Bar bar; @Before public void beforeClass() { MockitoAnnotations.openMocks(this); } @Test public void mockTest() { Mockito.when(bar.add(1, 2)).thenReturn(7); int result = foo.sum(1, 2); Assert.assertEquals(7, result); } }
-
下文中若使用注解方式定义mock对象不再重复说明,优先选择使用@RunWith(MockitoJUnitRunner.class)的方式。
一:创建被测试对象
1:创建被测对象
使用@InjectMocks注解
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@InjectMocks
private Foo foo;
@Test
public void mockTest() {
...
}
}
@InjectMocks的作用:标记应执行注入的字段(指此对象内的字段应该被自动的注入,注入的值来自@Mock或@Spy注解的字段)。
- 允许快速的mock和spy注入。
- 最大限度地减少重复的mock和spy注入代码。
@InjectMock成员变量的自动注入示例:
-
组合@Mock注解使用:
-
@RunWith(MockitoJUnitRunner.class) public class MockitoTest { //foo 对象内部的成员变量会自动被 @Mock 注解的生成的对象注入。 @InjectMocks private Foo foo; //bar 对象会自动的注入到 @InjectMocks 注解的对象的成员变量中去。 @Mock private Bar bar; @Test public void mockTest() { //先对mock对象的待测方法进行存根 Mockito.when(bar.add(1, 2)).thenReturn(7); int result = foo.sum(1, 2); //验证是否是存根返回的值 Assert.assertEqua