一、Mock定义
日常测试过程中,对一些不容易构造的对象,通过mock模拟对象的行为。例如A,B两个模块,A依赖B,B未开发完成,通过mockB对象,返回预期的结果给A调用。
二、Easymock
原理:Easymock通过动态代理实现模拟对象的创建
2.1 Maven中添加EasyMock依赖
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.3</version>
<scope>test</scope>
</dependency>
2.2 将查询接口注释
/**
* @author:jack
* @date 2021/5/30 19:25
* @des:todo
*/
@Service
public class GoodsService {
@Autowired
GoodDao goodDao;
//新增商品(注释内部实现,测试mock调用)
public void insert(Goods goods){
// return goodDao.insert(goods);
}
//查询所有商品(注释内部实现,测试mock调用)
public List<Goods> queryGoodList(){
// return goodDao.queryGoodList();
}
//根据id查询商品信息(注释内部实现,测试mock调用)
public Goods queryById(int id){
// return goodDao.queryById(id);
}
}
2.3 通过mock创建查询接口
@Test
public void testQueryGoodById(){
//创建期待的结果
Goods goods1 = new Goods();
goods1.setId(5);
goods1.setGoodName("电脑");
goods1.setGoodNum(99);
goods1.setGoodDes("这是一台电脑");
//1、创建Mock对象
GoodsService mock = EasyMock.createMock(GoodsService.class);
//2、模拟调用该mock对象抛出异常
//EasyMock.expect(mock.queryById(5)).andThrow(new RuntimeException());
//3、调用mock对象中的queryById接口进行模拟,EasyMock.anyInt())限制输入类型,根据数据类型,支持:anyInt(),anyShort(),anyByte(),angLong()...
// EasyMock.expect(mock.queryById(EasyMock.anyInt())).andReturn(goods1);
//4、测试该mock对象调用次数
EasyMock.expect(mock.queryById(5)).andReturn(goods1).times(3);
//5、重放Mock对象,将录制的对象代替真实的对象
EasyMock.replay(mock);
Goods good = mock.queryById(5);
//预期值和实际值进行断言
Assert.assertEquals(goods1,good);
//验证mock对象被调用
EasyMock.verify(mock);
注:
1、通过mock模拟GoodsService,mock调用queryById返回预期的结果,并进行断言。
2、EasyMock.createMock():必须用指定的参数调用指定的方法,不考虑调用方法的次序,调用未预期的方法会导致失败。
EasyMock.createStrictMock():必须按次序调用指定的方法,调用未逾期的方法会失败。
GoodsService mock = EasyMock.createMock(GoodsService.class);
3、通过EasyMock.anyInt()对传入参数进行校验,类似泛型,还支持:EasyMock.anyShort()、EasyMock.anyByte()、EasyMock.anyLong()、EasyMock.anyFloat()、EasyMock.anyDouble()、EasyMock.anyBoolean(),输入类型不符的参数会报错。
EasyMock.expect(mock.queryById(EasyMock.anyInt())).andReturn(goods1);
4、 通过andReturns设置调用后返回的结果。
EasyMock.expect(mock.queryById(5)).andReturn(goods1);
5、测试方法调用的次数,与预期次数不符报错。
EasyMock.expect(mock.queryById(5)).andReturn(goods1).times(3);
6、模拟调用方法返回异常信息(常用)
EasyMock.expect(mock.queryById(5)).andThrow(new RuntimeException());
EasyMock.replay(mock);
Goods goods = mock.queryById(5);
Assert.assertNull(goods);
EasyMock.verify(mock);
2.4 mock无返回值对象
将GoodService中的insert()方法改为无返回值(应该为Boolean类型)
此时想mock插入对象的插入方法,需要进行修改:
正常mock:
mock.insert(goods);
EasyMock.expectLastCall().anyTimes();
异常mock:
EasyMock.expectLastCall().anyTimes();
EasyMock.expectLastCall().andThrow(new RuntimeException()).anyTimes();
2.5 mock多次调用返回不同的值
在测试用例的执行中,会有需求多次运行的过程中返回不同的值,这里简单举例:
EasyMock.expect(queryGoodList.next()).andReturn(true).times(5).andReturn(false).times(2);
三、总结
测试过程中,mock能大大的提高我们的效率,模拟各种想要的参数,得到想要的结果,但是会隐藏mock对象中较多的bug,导致测试不充分。在任何情况下,mock都不应该是我们的第一选择,在真实存在的场景下进行测试,才能发现更多的问题。
本文简单的介绍Easymock的使用,基本覆盖常用的mock场景,有兴趣深入的同学可阅读此篇文章:https://tech.youzan.com/mock/。