Mock:PowerMockito,EasyMock,Mockito

一.什么是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的使用:

  1. MOCK通过参数传递的对象

需要测试的目标代码

Public class ConvertController{

@Resource

    private ConvertServiceImpl convertservice;

    Public APIResult convert(HttpServletRequest request){

          Return convertservice.getConvertResult(request.getInputStream(),

request.getContentType());

}

}

测试方法

使用注解时需加上:
     @Before//在执行所有@Test之前执行

    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());

   }

 

  1. mock方法内部new出来的对象

目标代码

Public class create{

public boolean callInternalInstance(String path) { 

File file = new File(path); 

Return file.exits();

}

}

测试代码

@RunWith(PowerMockRunner.class) 

Public class createtest{

@PrepareForTest(Create.class)@Test

Public void test callInternalInstance(){

File file = PowerMockito.mock(File.class); 

PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file); 

PowerMockito.when(file.exists()).thenReturn(true); 

}

}

  1. 静态方法的mock:

测试目标代码: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);

 

备注:要加注解@PrepareForTestIoutils.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 clazz):不容易构造的类型可以用这种方式,如:any(InputStream.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.assertSameexpected,actual:比较两个参数是否相等,适用于八大基本数据类型

Assert.assertSame(Object expected,Object actual):比较两个对象的地址是  否相等不能比较内容

Assert.assertTrue():如果为true,则运行成功,反正运行失败,并且无错误提示

Assert.assertSameString message,Object[] expected,Object[] actual:比较两个数组是否相等(数组长度和对应数组元素),若不相等则返回message

Assert.assertNotNull():断言不为空

Assert.assertNull():断言为空

 

  • 验证方法是否被调用:verify()

备注:

  1. verify是负责验证的函数,接收的是mock的对象,不能接收实例对象
  2. 验证不成功,直接报错
  3. 使用verify()可及早发现自己的错误,预期的方法没有调用,实际调用肯定出错
  4. Verify()方法应该放在实际调用之后;

Mockito.verify(list).get(0);//验证get(0)被调用

Mockito.verify(listnever()).get(0);//验证get(0)没有被调用

Mockito.verify(listtimes(n)).get(0);//验证get(0)被调用了n

Mockito.verify(listatLeast(n)).get(0);//验证get(0)至少被调用了n

 

你可能感兴趣的:(测试)