Mockito简介摘自官网,Mockito是一个非常优秀mock框架。他用简单易用的API让单元测试的编写更加简洁优雅。Mockito测试用例可读性高,校验规则清晰。Mockito社区活跃,StackOverflow投票Mockito是最受欢迎的java mock框架。
添加maven依赖
<dependencies> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>核心利用MockitoJunitRunner来跑Junit的单元测试@RunWith(MockitoJUnitRunner.class)
// 使用Junit的MockitoRunner开启Mockito测试 @RunWith(MockitoJUnitRunner.class) public class SimpleUseMockito { /** * 基于Mockito的校验操作行为 */ @Test public void testSimpleVerifyBehavior(){ // 使用mockito的静态方法生成一个mock 对象 ArrayList<Integer> list = mock(ArrayList.class); System.out.println(list.getClass()); // mock出来的对象的一些行为 list.add(0); list.add(1); list.clear(); // 使用mockito 的verify 方法来校验操作步骤 verify(list).add(0); verify(list).add(1); verify(list).clear(); } }使用MockitoAnnotations.init(testClass) 来初始化一个需要mock的类
@Mock 注解来表示该对象是mock出来的
public class UseMockitoByAnnotation { @Mock List<Integer> list; @Before public void init() { MockitoAnnotations.initMocks(this); } @Test public void test1() { doReturn(1).when(list).get(0); assertThat(list.get(0), equalTo(1)); } @After public void destroy() { } }MockitoJunit.rule()创建一个Junit的Rule 其他使用方式与注解和Runner类似
public class UseMockitoByRule { @Rule public MockitoRule mockitorule = MockitoJUnit.rule(); @Mock List<Integer> list; @Test public void test1() { doReturn(1).when(list).get(0); assertThat(list.get(0), equalTo(1)); } }可以创建一个真实对象的spy,当使用spy对象的时候会真正调用真实对象的方法(除非改方法被stub)
/** * 可以创建一个真实对象的spy,当使用spy对象的时候会真正调用真实对象的方法(除非改方法被stub) * 跟mock不同的是,利用Spy可以做到部分的mock,只在需要mock的部分做stubbing即可完成mock */ @Test public void testSpy() { // 1. 创建真实的对象 List<Integer> realList = new ArrayList<>(); // 调用spy传入真实对象返回改对象的SPY List<Integer> spy = spy(realList); // 真实调用方法 spy.add(1); spy.add(2); spy.add(3); assertThat(spy.size(), equalTo(3)); // 如果需要mock处理 做一个特殊的stubbing 即可 when(spy.get(0)).thenReturn(100); assertThat(spy.get(0), equalTo(100)); }在spy调用真实对象的时候可能会出现异常,此时用doXXX方法来解决
@Test public void testSpyGotcha() { // 1. 创建真实的对象 List<Integer> realList = new ArrayList<>(); // 调用spy传入真实对象返回改对象的SPY List<Integer> spy = spy(realList); try { // 因为会调用真实对象 所有spy.get(0) 会报索引越界 when(spy.get(0)).thenReturn(1); } catch (Exception e) { assertThat(e, instanceOf(IndexOutOfBoundsException.class)); } // 使用doReturn 来解决这个问题 doReturn(1).when(spy).get(0); assertThat(spy.get(0),equalTo(1)); }mockito在做测试时候有时候不仅需要对测试的返回值进行断言,有时也会对调用的方法参数传入的具体参数值进行断言,此时可以使用ArgumentCaptor来捕获参数值
需要特别注意的是ArgumentCaptor只能用在verfication的时候不能使用在stub中,在stubbing中使用ArgumentCaptor会减少测试的可靠性,因为ArgumentCaptor是在assert块之外创建的,也会因为stubbing的方法没有调用导致没有参数可以捕获导致不好定位错误。
/** * argument.capture() 捕获方法参数 * argument.getValue() 获取方法参数值,如果方法进行了多次调用,它将返回最后一个参数值 * argument.getAllValues() 方法进行多次调用后,返回多个参数值 */ @Test public void testArgumentCapturing() { ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class); List<String> list1 = mock(List.class); List<String> list2 = mock(List.class); list1.add("jack"); list2.add("tom"); list2.add("tomcat"); // 在verify中使用 使用ArgumentCaptor 捕获传入的参数 verify(list1, times(1)).add(argumentCaptor.capture()); assertThat("jack", equalTo(argumentCaptor.getValue())); verify(list2, times(2)).add(argumentCaptor.capture()); assertArrayEquals(new String[]{"jack", "tom", "tomcat"}, argumentCaptor.getAllValues().toArray()); }BDD ( Behavior Driver Delopment )基于行为驱动开发,具体参考wiki或者其他关于BDD的相关资料
@Test public void testSupport4BDD(){ List<Integer> mock = mock(List.class); // give given(mock.get(0)).willReturn(100); // when Integer result = mock.get(0); // then assertThat(result,equalTo(100)); }mock可以被序列化,使用mockito的序列化支持可以在一些依赖需要序列化的时候进行mock
List serializableMock = mock(List.class, withSettings().serializable());使用方法在classpath下创建一个mockito-extensions目录创建一个org.mockito.plugins.MockMaker文件内容为mock-maker-inline即可mock final类型
使用过程中需要注意参数统配的顺序,范围越大的统配放在后面会覆盖范围具体的统配条件
@Test public void testArgument() { MockitoWildCardArgumentClass mock = mock(MockitoWildCardArgumentClass.class); // stub anyString传入任意String anyInt任意int anyCollection任意collection的子类 any()任意一个class值保证编译不报错 when(mock.function1(anyString(),anyInt(),anyCollection(),any())).thenReturn("test arg"); assertThat(mock.function1("1",1, Collections.emptyList(),"s"),equalTo("test arg")); assertThat(mock.function1("2",2, Collections.emptySet(),"s"),equalTo("test arg")); } /** * 部分统配 部分特殊定制值eq()方法 */ @Test public void testWildCardArgument() { MockitoWildCardArgumentClass mock = mock(MockitoWildCardArgumentClass.class); // stub 中其中某一些参数需要指定 则用到eq 如果不使用eq直接使用会报 InvalidUseOfMatchersException when(mock.function1(anyString(),eq(1),anyCollection(),any())).thenReturn("eq 1"); when(mock.function1(anyString(),eq(2),anyCollection(),any())).thenReturn("eq 2"); assertThat(mock.function1("1",1, Collections.emptyList(),"s"),equalTo("eq 1")); assertThat(mock.function1("2",2, Collections.emptySet(),"s"),equalTo("eq 2")); } /** * 统配的使用顺序 */ @Test public void testWildCardArgumentOrderErorr() { MockitoWildCardArgumentClass mock = mock(MockitoWildCardArgumentClass.class); // 在使用统配参数的时候需要注意使用的顺序 必须把通用的放在之前 如果把通用的放在最后会覆盖之前特别定制的参数 when(mock.function1(anyString(),eq(1),anyCollection(),any())).thenReturn("eq 1"); when(mock.function1(anyString(),eq(2),anyCollection(),any())).thenReturn("eq 2"); // 统配在最后 会覆盖之前特殊处理的stub when(mock.function1(anyString(),anyInt(),anyCollection(),any())).thenReturn("eq anyInt"); assertThat(mock.function1("1",1, Collections.emptyList(),"s"),equalTo("eq anyInt")); assertThat(mock.function1("2",2, Collections.emptySet(),"s"),equalTo("eq anyInt")); } /** * 统配的使用顺序 */ @Test public void testWildCardArgumentOrderSuccess() { MockitoWildCardArgumentClass mock = mock(MockitoWildCardArgumentClass.class); // 在使用统配参数的时候需要注意使用的顺序 必须把通用的放在之前 如果把通用的放在最后会覆盖之前特别定制的参数 // 统配的在之前 正常匹配特殊定制的 when(mock.function1(anyString(),anyInt(),anyCollection(),any())).thenReturn("eq anyInt"); when(mock.function1(anyString(),eq(1),anyCollection(),any())).thenReturn("eq 1"); when(mock.function1(anyString(),eq(2),anyCollection(),any())).thenReturn("eq 2"); assertThat(mock.function1("1",1, Collections.emptyList(),"s"),equalTo("eq 1")); assertThat(mock.function1("2",2, Collections.emptySet(),"s"),equalTo("eq 2")); }