一.什么是MOCK?
模拟真实对象行为的一个假的对象,该对象中的数据可以按照自己的期望赋予。
二.为什么要MOCK?
1.在单体测试过程中,有的对象很难构造或者获取;
2.调用的别人的逻辑还没有实现。
三.PowerMockito,EasyMock,Mockito的区别:
EasyMock:EasyMock 使用动态代理,能够创建任何接口的基本实现,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。
使用步骤:
第一步:使用 EasyMock 生成 Mock 对象;
第二步:录制 Mock 对象的预期行为和输出;
第三步:将 Mock 对象切换到 播放 状态;
第四步:调用 Mock 对象方法进行单元测试;
第五步:对 Mock 对象的行为进行验证。
Mockito:可校验哪些函数被调用,消除了对期望行为的需要
使用步骤:
第一步:使用 mockito 生成 Mock 对象;
第二步:定义(并非录制) Mock 对象的行为和输出(expectations部分);
第三步:调用 Mock 对象方法进行单元测试;
第四步:对 Mock 对象的行为进行验证。
PowerMock:是在EasyMock 以及 Mockito上的扩展,可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟
四.PowerMock的常用注解:
@RunWith(PowerMockRunner.class)
@PrepareForTest({YourClass.class})//模拟静态,final,私有方法等时需加上
备注:以上两个备注一般同时使用
@InjectMocks:mock将要注入的实例
@Mock:创建一个mock,该mock对象所有方法被置空
@Spy:创建一个mock,该mock对象所有方法都是真实的
五.PowerMockito的使用:
需要测试的目标代码 Public class ConvertController{ @Resource private ConvertServiceImpl convertservice; Public APIResult convert(HttpServletRequest request){ Return convertservice.getConvertResult(request.getInputStream(), request.getContentType()); } } 测试方法 使用注解时需加上: public void setUp() throws Exception { controller = new ConvertController();//实例对象 convertservice = Mockito.mock(ConvertServiceImpl.class); // 创建Mock对象 Whitebox.setInternalState(controller, "convertservice", convertservice); // 注入依赖对象 } @Test public void testconvert() throws Exception { APIResult api = new APIResult(0, "error"); //mock一个HttpServletRequest对象 HttpServletRequest request=PowerMockito.mock(HttpServletRequest.class); //调用convertservice.getConvertResult(args1,args2)时返回的预期结果api Mockito.when(convertservice.getConvertResult(request.getInputStream(); request.getContentType())).thenReturn(api); //调用实际的业务代码,得出运行结果 APIResult result = controller.convert(request); //预期结果和实际结果进行比较 Assert.assertEquals(result.getCode(),api.getCode()); Assert.assertEquals(result.getErrMsg(),api.getErrMsg()); } |
目标代码 Public class create{
} 测试代码
|
测试目标代码:Ioutils的静态方法toByteArray(inputsytream) Byte[] by=Ioutils.toByteArray(inputsytream); 测试用例代码: Byte[] bytes=new byte[]{1,2,3}; PowerMockito.mockStatic(IOUtils.class); PowerMockito.when(IOUtils.toByteArray(any(InputStream.class))).thenReturn(bytes); |
备注:要加注解@PrepareForTest(Ioutils.Class)
六.@Spy和@Mock的区别:
1.对于@Mock注释的类的一般用法:
When(file.exits()).thenReturn(true);//exits()方法会执行一次,然后返回希望的结果true
2.对于@Spy注释的类的一般用法:
doReturn(true).when(file).exits();//exits()方法不会执行,直接返回预期结果true
3.说明:
1>.使用@Mock生成的类,所有方法都不是真实的方法,而且返回值都是NULL。
2>.使用@Spy生成的类,所有方法都是真实方法,返回值都是和真实方法一样的,并且@spy修饰的对象都必须先手动new出来,。
@spy的用法 List list=new LinkedList(); List spy=spy(list); 要调用mock的值: Mockito.When(spy.size()).thenReturn(100);//打桩 System.out.println(spy.size());//100 调用实际的值: System.out.println(spy.size());//0
|
4.使用场景:
1>.当对象的大部分方法实际调用,只有一小部分需要返回我们预期的值时使用@spy;
2>当某个对象的大部分或者全部方法都需要返回我们希望的值时使用@Mock
七.参数匹配问题
在mock一个方法时,对于方法的参数要求是很严格的,只有要执行的方法的参数与mock的方法中的参数相匹配时,mock方法才起作用,(这里很容易导致空指针异常)
PowerMock提供提供了精确匹配和模糊匹配的方式:
1.精确匹配:
常用于String,int,boolean,long,double等可以直接构造的参数类型
Public class Usertest{ @Test Public void testgetBookType(){ Book book=PowerMockito.mock(Book.class); When(book.getType(Mockito.eq(“Jane Eyre”))).thenReturn(“novel”); //执行该方法并且参数为“Jane Eyre”时返回“novel” } } |
2.模糊匹配:
Public class Usertest{ @Test Public void testgetBookType(){ Book book=PowerMockito.mock(Book.class); When(book.getType(Mockito.startwith(Jane))).thenReturn(“Jane Eyre”); //参数以“Jane”开始的方法都返回“Jane Eyre” } } |
3.任意匹配(可以解决大部分问题):
无论入参是什么值,都认为是匹配的,常用的有:anyString,anyInt,anyLong等any(Class
@Test public void testgetConvertResult1() throws Exception { // 测试文件上传方式 contentType = "multipart/form-data"; APIResult result = convert.getConvertResult(any(InputStream.class), contentType); Assert.assertEquals(result.toString(), "{\"code\":400}"); } |
可能需要手动导包:
import static org.mockito.Matchers.*;
八.单体测试常用的断言:
Assert.assertSame(expected,actual):比较两个参数是否相等,适用于八大基本数据类型
Assert.assertSame(Object expected,Object actual):比较两个对象的地址是 否相等不能比较内容
Assert.assertTrue():如果为true,则运行成功,反正运行失败,并且无错误提示
Assert.assertSame(String message,Object[] expected,Object[] actual):比较两个数组是否相等(数组长度和对应数组元素),若不相等则返回message
Assert.assertNotNull():断言不为空
Assert.assertNull():断言为空
备注:
Mockito.verify(list).get(0);//验证get(0)被调用 Mockito.verify(list,never()).get(0);//验证get(0)没有被调用 Mockito.verify(list,times(n)).get(0);//验证get(0)被调用了n次 Mockito.verify(list,atLeast(n)).get(0);//验证get(0)至少被调用了n次 |