Mockito基本使用
- 创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中。
- 执行测试代码。
- 校验测试代码是否执行正确。
Maven 依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.0.111-beta</version>
</dependency>
创建Mock对象
调用mock静态方法来创建一个Mock对象,mock方法接收一个class类型,即需要mock的类型。
@Test
public void createMockObject() {
// 使用 mock 静态方法创建 Mock 对象.
List mockedList = mock(List.class);
Assert.assertTrue(mockedList instanceof List);
// mock 方法不仅可以 Mock 接口类, 还可以 Mock 具体的类型.
ArrayList mockedArrayList = mock(ArrayList.class);
Assert.assertTrue(mockedArrayList instanceof List);
Assert.assertTrue(mockedArrayList instanceof ArrayList);
}
配置Mock对象
(1)使用when(...).thenReturn(...)
方法链来定义一个行为
- 方法链不仅仅要匹配方法的调用, 而且要方法的参数一样才行
- 方法链可以指定多个返回值, 当这样做后, 如果多次调用指定的方法, 那么这个方法会依次返回这些值
@Test
public void configMockObject() {
List mockedList = mock(List.class);
// 我们定制了当调用 mockedList.add("one") 时, 返回 true
when(mockedList.add("one")).thenReturn(true);
// 当调用 mockedList.size() 时, 返回 1
when(mockedList.size()).thenReturn(1);
Assert.assertTrue(mockedList.add("one"));
// 因为我们没有定制 add("two"), 因此返回默认值, 即 false.
Assert.assertFalse(mockedList.add("two"));
Assert.assertEquals(mockedList.size(), 1);
Iterator i = mock(Iterator.class);
when(i.next()).thenReturn("Hello,").thenReturn("Mockito!");
String result = i.next() + " " + i.next();
//assert
Assert.assertEquals("Hello, Mockito!", result);
}
when(i.next()).thenReturn("Hello,").thenReturn("Mockito!");
// 这句代码表示:
// 第一次调用 i.next() 时返回 "Hello,", 第二次调用 i.next() 时返回 "Mockito!".
(2)指定一个抛出异常,使用doThrow(ExceptionX).when(x).methodCall
- 当调用了 x.methodCall 方法后, 抛出异常 ExceptionX.
@Test(expected = NoSuchElementException.class)
public void testForIOException() throws Exception {
Iterator i = mock(Iterator.class);
// 第一次调用 i.next() 时返回 "Hello,", 第二次调用 i.next() 时返回 "Mockito!".
when(i.next()).thenReturn("Hello,").thenReturn("Mockito!");
String result = i.next() + " " + i.next(); // 调用两次i.next()
Assert.assertEquals("Hello, Mockito!", result);
// 当第三次调用 i.next() 后, 抛出异常 NoSuchElementException.
// (因为i 这个迭代器只有两个元素)
doThrow(new NoSuchElementException()).when(i).next();
// 第三次调用 i.next() 抛出异常
i.next();
}
校验 Mock 对象的方法调用
Mockito 会追踪 Mock 对象的所用方法调用和调用方法时所传递的参数。我们可以通过 verify() 静态方法来来校验指定的方法调用是否满足断言。
@Test
public void testVerify() {
List mockedList = mock(List.class);
mockedList.add("one");
mockedList.add("two");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
when(mockedList.size()).thenReturn(5);
Assert.assertEquals(mockedList.size(), 5);
// mockedList.add("one") 至少被调用了 1 次(atLeastOnce)
verify(mockedList, atLeastOnce()).add("one");
// mockedList.add("two") 被调用了 1 次(times(1))
verify(mockedList, times(1)).add("two");
// mockedList.add("three times") 被调用了 3 次(times(3))
verify(mockedList, times(3)).add("three times");
// mockedList.isEmpty() 从未被调用(never)
verify(mockedList, never()).isEmpty();
}
使用 spy() 部分模拟对象
Mockito 提供的 spy 方法可以包装一个真实的 Java 对象,并返回一个包装后的新对象。若没有特别配置的话,对这个新对象的所有方法调用,都会委派给实际的 Java 对象。
@Test
public void testSpy() {
// 这个例子中我们实例化了一个 LinkedList 对象
List list = new LinkedList();
// 使用 spy() 方法对 list 对象进行部分模拟
List spy = spy(list);
// 对 spy.size() 进行定制.
// 使用 when(...).thenReturn(...) 方法链来规定 spy.size() 方法返回值是 100
when(spy.size()).thenReturn(100);
// 向 spy 添加两个元素
spy.add("one");
spy.add("two");
// 因为我们没有对 get(0), get(1) 方法进行定制,
// 因此这些调用其实是调用的真实对象的方法.
Assert.assertEquals(spy.get(0), "one");
Assert.assertEquals(spy.get(1), "two");
Assert.assertEquals(spy.size(), 100);
}
参数捕获
Mockito 允准我们捕获一个 Mock 对象的方法调用所传递的参数。
@Test
public void testCaptureArgument() {
List<String> list = Arrays.asList("1", "2");
List mockedList = mock(List.class);
ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
mockedList.addAll(list);
// verify(mockedList).addAll(argument.capture()) 语句来获取 mockedList.addAll 方法所传递的实参 list.
verify(mockedList).addAll(argument.capture());
Assert.assertEquals(2, argument.getValue().size());
Assert.assertEquals(list, argument.getValue());
}