什么是Mock?
mock测试就是在测试过程中,对于某些不容易构造(如HttpSerlvertRequest就必须在Servlet容器中才能构造出来)或者不容易获取比较复杂的对象(如JDBC中的ResultSet对象),用一个虚拟的对象(Mock对象)来创建以便测试的测试方法。
Mock最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能帮你模拟出这些依赖。并帮你验证所调用的依赖的行为。
比如有这样一段依赖代码:
当我们需要测试A类的时候,如果没有Mock。则我们需要把整个依赖树都构建出来(先构建E,再构建D,再构建C,在构建B,最后才能测试A),而使用Mock的话,就可以将结构分解开,像下面这样:
用mock B和mock C的房间,将D,E对象隔离。
Mockito框架
Mockito是Java单元测试Mock框架。灵活而方便。maven配置
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
在测试类中静态导入Mockito
import static org.mockito.Mockito.*;
1.Mockito支持使用mock()静态方法创建模拟对象,Mockito可以使用verify()方法来确认某些方法是否被调用过。如下所示:
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
2.Stubbing表示一次插桩,它的形式是 when(x).thenReturn(y),用于指定mock的行为。Stubbing的示例代码如下:
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRemoteHost()).thenReturn("localhost");
我们使用when(…).thenReturn(…)方法链来定义一个行为。例如“when(mockedList.add(“one”)).thenReturn(true)”表示:当调用了mockedList.add(“one”),那么返回true。并且要注意的是,when(…).thenReturn(…)方法链不仅仅要匹配方法的调用,而且要方法的参数一样才能。另外,when(…).thenReturn(…)方法链可以指定多个返回值,当这样做后,如果多次调用指定的方法,那么这个方法会依次返回这些值。例如“when(i.next()).thenReturn(“Hello,”).thenReturn(“Mockito!”)”,这句话表示:第一次调用i.next()时返回“Hello,”,第二次调用i.next()返回“Mockito!”.
3.Mockito还可以指定异常情况,如下所示:
@Test(expected = NoSuchElementException.class)
public void testForIOException() throws Exception {
Iterator i = mock(Iterator.class);
when(i.next()).thenReturn("Hello,").thenReturn("Mockito!"); // 1
String result = i.next() + " " + i.next(); // 2
Assert.assertEquals("Hello, Mockito!", result);
doThrow(new NoSuchElementException()).when(i).next(); // 3
i.next(); // 4
}
上面这个例子中,第3步我们使用了一个新语法:doThrow(ExceptionX).when(x).methodCall, 它的含义是:当调用了x.methodCall方法后,抛出异常ExceptionX.因此doThrow(new NoSuchElementException()).when(i).next() 的含义就是:当第三次调用i.next()后,抛出异常NoSuchElementException。(因为 i 这个迭代器只有两个元素)
4.校验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);
verify(mockedList, atLeastOnce()).add("one");//1
verify(mockedList, times(1)).add("two");//2
verify(mockedList, times(3)).add("three times");//3
verify(mockedList, never()).isEmpty();//4
}
上面例子中,有4步校验:
- 第一句校验 mockedList.add(“one”) 至少被调用了 1 次(atLeastOnce)
- 第二句校验 mockedList.add(“two”) 被调用了 1 次(times(1))
- 第三句校验 mockedList.add(“three times”) 被调用了 3 次(times(3))
- 第四句校验 mockedList.isEmpty() 从未被调用(never)
5.参数匹配器允许灵活地验证或者Stubbing,如下所示:
//stubbing using built-in anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn("element");
//stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
//following prints "element"
System.out.println(mockedList.get(999));
//you can also verify using an argument matcher
verify(mockedList).get(anyInt());
最后编辑:Jeebiz 更新时间:2024-11-14 21:58