本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。大家好,我是阿芬。很多时候在日常工作中,我们需要同事相互配合完成某些功能,所以我们经常会遇到服务或应用中不同模块相互依赖的场景。例如下面的场景,serviceA中的methodA()方法依赖于serviceB中的methodB()方法返回运行结果。那么如果我们要为我们的methodA()方法写单元测试,就需要等其他同事的methodB()方法开发出来了。有什么方法可以跳过或模拟方法B的输出吗?这就引出了我们今天的主角Mockito,一个优秀的Mock测试框架。通过使用Mock技术,我们可以避免开发停滞。Mock技术的作用是在测试和自测阶段隔离服务之间的依赖关系,让开发者在自己的应用中模拟需要依赖的外部接口。它的构建是为了确保它不会受到外界开发进度的影响。今天要说的Mockito就是一个优秀的Mock框架。MockitoMockito是一个mocking框架,味道真的不错。它可以让你用干净简单的API编写漂亮的测试。Mockito不会让您宿醉,因为测试非常可读,并且会产生干净的验证错误。模拟框架。它允许您使用干净简单的API编写漂亮的测试。Mockito的可读性很好,不会被感动和迷惑,产生的验证错误也一目了然。官网地址:https://site.mockito.org/中文文档:https://github.com/hehonghui/mockito-doc-zh#0测试用例1首先在项目的pom文件中添加依赖,我们添加mockito和junit依赖项。org.mockitomockito-all1.9.5测试junitjunit4.11test接下来我们写一个简单的测试用例,模拟一个ListObject,先添加几个元素,然后验证添加的交互是否符合我们的预期。@TestpublicvoidtestVerify()throwsException{//创建模拟对象ListmockedList=mock(List.class);mockedList.add("test1");mockedList.add("test2");mockedList.add("test2");mockedList.clear();//验证是否执行了add("test1")操作verify(mockedList).add("test1");//同上验证是否执行了add("test1")操作,默认为time(1)verify(mockedList,times(1)).add("test1");//验证add("test2")操作是否执行了3次//verify(mockedList,times(3)).add("test2");verify(mockedList).clear();}运行上面的测试用例后,结果如下,测试用例通过。当我们释放verify(mockedList,times(3)).add("test2");行代码运行,我们可以看到测试用例失败了,提示的错误是我们期望执行3次,但结果实际上只执行了2次add("test2")操作。上面的测试用例是为了验证对应方法的执行次数是否与预期一致。除了准确次数,还有最多,至少,从未等待的验证方法,如下所示://准确次数verify(mockedList,times(3).add("test2");//至少1次验证(mockedList,atLeastOnce()).add("test2");//至少2次验证(mockedList,atLeast(2)).add("test2");//最多5次验证(mockedList,atMost(5)).add("test2");测试用例2通过设置值或打桩的方式预先设置参数,如下图,当执行get(0)操作时,我们通过thenReturn()方法,执行get(1)操作时抛出空指针异常,运行结果如下图所示:@TestpublicvoidtestWhen()throwsException{LinkedListmockedList=mock(LinkedList.class);//设置值,通常称为打桩when(mockedList.get(0)).thenReturn("hello");when(mockedList.get(1)).thenThrow(newNullPointerException());System.out.println(mockedList.get(0));//这里会打印“null”因为get(2)没有设置System.out.println(mockedList.get(2));//这里会抛出异常System.out.println(mockedList.get(1));//验证是否执行了get(0)操作verify(mockedList).get(0);}可以看到当我们调用get(0)和get(1)时,控制台成功抛出异常。这种方法通常称为存根。除了使用when...thenReturn方法外,还有另一种形式可以表达。代码如下:@TestpublicvoidtestDoReturn()throwsException{IteratormockedList=mock(Iterator.class);doReturn("hello").when(mockedList).next();Objectnext=mockedList.next();System.out.println(next);doReturn("world").when(mockedList).next();Objectnext2=mockedList.next();System.out.println(next2);//上面的过程也可以这样写doReturn("test1","test2").when(mockedList).next();Objectnext3=mockedList.next();System.out.println(next3);Objectnext4=mockedList.next();System.out.println(next4);}运行结果如下,也可以使用doThrow()方法抛出异常:测试用例3在日常开发中,我们通过保证方法的时效性,或者说我们想保证某个方法执行多长时间必须在里面执行,这时候我们也可以使用mock方法来验证我们的方法是否满足要求。代码如下:@TestpublicvoidtestTimeout()throwsException{HttpServicemock=mock(HttpService.class);Stringurl="http://www.xxx.com";mock.getRequest(url);verify(mock,timeout(100)).getRequest(url);//超时时间后,用自定义的验证方式进行验证,newTimeout(100,customVer)).getRequest(url);}Mockito还有很多API可以使用。更多使用方法可以参考本网站。https://www.tutorialspoint.com/mockito/mockito_timeouts.htm,有比较详细的介绍。