
向很多开源社区提交代码是需要做完整的 单元测试 的,其中 mock 目标实例、给 mock 对象打桩 等操作可以极大提高测试代码的效率和可读性
本章节基于 Mockito BDDMockito 的 API DEMO 熟悉一些基本操作,Spring Test 包含对应依赖
Mockito BDDMockito其中 BDD 代表 behavior driven deployment,我理解就是让测试代码语义更接近现实行为,比如
语义化的东西强行解释总感觉生硬mock
@Test
public void mockDemo() {
List mock = mock(List.class);
mock.add("test");
mock.add("test1");
mock.add("test1");
mock.get(0);
// verify:是否调用目标方法
verify(mock).add("test");
// BDD style
then(mock).should().add("test");
// 目标方法调用一次
verify(mock, times(1)).add("test");
then(mock).should(times(1)).add("test");
// 目标方法至少调用 2 次
verify(mock, atLeast(2)).add("test1");
then(mock).should(atLeast(2)).add("test1");
// 目标方法最多调用 2 次
verify(mock, atMost(2)).add("test1");
then(mock).should(atMost(2)).add("test1");
// 目标方法未调用
verify(mock, never()).add("test2");
then(mock).should(never()).add("test2");
// error
verify(mock).add("test2");
verify(mock).get(1);
}
@Test
public void stubDemo() {
ArrayList mock = mock(ArrayList.class);
// 打桩
when(mock.get(0)).thenReturn("a");
// BDD-style
given(mock.get(0)).willReturn("a");
when(mock.get(1)).thenThrow(new RuntimeException("test"));
// given(mock.get(1)).willThrow(new RuntimeException("test"));
doThrow(new RuntimeException("void")).when(mock).clear();
// willThrow(new RuntimeException("void")).given(mock).clear();
System.out.println(mock.get(0));
try {
mock.get(1);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println(mock.get(2));
}
@Test
public void matcherDemo() {
ArrayList mock = mock(ArrayList.class);
// 匹配任意 int
when(mock.get(anyInt())).thenReturn("meta");
given(mock.get(anyInt())).willReturn("meta");
// 所有的方法都要使用 matcher
when(mock.subList(anyInt(), eq(1))).thenReturn(new ArrayList() {{
add("meta2");
}});
given(mock.subList(anyInt(), eq(1))).willReturn(new ArrayList() {{
add("meta2");
}});
System.out.println(mock.get(12));
System.out.println(mock.subList(3, 1));
// then 阶段也可以使用
verify(mock).get(anyInt());
then(mock).should().get(anyInt());
}
我指的自然语义就是 given ... when ... then ...inorder
@Test
public void orderDemo() {
ArrayList mock = mock(ArrayList.class);
LinkedList mock2 = mock(LinkedList.class);
mock.add(1);
mock.add(2);
mock2.add(1);
mock2.add(2);
// 可以有多个实例
InOrder inOrder = inOrder(mock, mock2);
inOrder.verify(mock).add(1);
inOrder.verify(mock).add(2);
// correct,可以跳过
// inOrder.verify(mock2).add(2);
inOrder.verify(mock2).add(1);
// BDD-style
then(mock2).should(inOrder).add(2);
// error
inOrder.verify(mock).add(1);
}
@Test
public void consecutiveDemo() {
ArrayList mock = mock(ArrayList.class);
when(mock.get(anyInt()))
.thenReturn(0, 1, 2);
// 0
System.out.println(mock.get(0));
// 1
System.out.println(mock.get(1));
// 2
System.out.println(mock.get(2));
// 2
System.out.println(mock.get(3));
// 清空
reset(mock);
System.out.println(mock.get(0));
}
@Test
public void answerDemo() {
ArrayList mock = mock(ArrayList.class);
when(mock.get(anyInt()))
.then(invocation -> {
Object argument = invocation.getArgument(0);
return argument + "r";
});
// BDD-style
given(mock.get(anyInt()))
.will(invocationOnMock -> {
Object argument = invocationOnMock.getArgument(0);
return argument + "r";
});
System.out.println(mock.get(0));
System.out.println(mock.get(1));
}
@Test
public void spyDemo() {
List list = new LinkedList();
List spy = spy(list);
spy.add(1);
when(spy.size()).thenReturn(10);
// BDD-style
given(spy.size()).willReturn(10);
System.out.println(spy.get(0));
System.out.println(spy.size());
// spy 只是一个 copy,所以 list 上的操作不影响 spy
list.add(2);
spy.forEach(System.out::println);
}
@Test
public void oneLinerStubsDemo() {
HelloService helloService = when(mock(HelloService.class).hello())
.thenReturn("hello world")
.getMock();
// BDD-style
HelloService helloService2 = given(mock(HelloService.class).hello())
.willReturn("hello world 2")
.getMock();
System.out.println(helloService.hello());
System.out.println(helloService2.hello());
}
本文介绍一些基于 Mockito BDDMockito 的 DEMO,旨在写出实用又好看的 单元测试
完整示例 demo