java单元测试之mock篇
java单元测试之mock篇
- 一、什么是mock?
- 二、为什么要进行mock?
- 三、IDEA中使用Mock
- 3.1、引入mock所需依赖
- 3.1、IDEA单元测试必备快捷键
- 3.2、Mock测试相关注解
- @Mock注解
- @InjectMocks注解
- 调用PowerMockito.spy()方法
- Mock使用方式或者技巧
- 静态方法mockStatic
- @PrepareForTest的使用场景
- 阻止代码初始化,包括static{}静态代码块或者static变量的初始化
- 3.3、问题
一、什么是mock?
Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取的比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。
二、为什么要进行mock?
Mock是为了解决不同的单元之间由于耦合而难于开发、测试的问题。所以,Mock既能出现在单元测试中,也会出现在集成测试、系统测试过程中。Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
比如一段代码有这样的依赖:
当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:
三、IDEA中使用Mock
3.1、引入mock所需依赖
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.9.0</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-core</artifactId><version>2.0.9</version></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.9</version></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.9</version><scope>test</scope></dependency>
3.1、IDEA单元测试必备快捷键
新建UT——Ctrl + Shift + T
双击所要进行单元测试的类,点击Ctrl + Shift + T,新建或者跳转到已创建的UT,这里我们点击Create New Test…新建UT,选择JUnit4,选择好需要测试的方法后点击OK。
3.2、Mock测试相关注解
@Mock注解
@RunWith(PowerMockRunner.class)
public class AnnouncementManagerImplTest {@MockAnnouncementMapper announcementMapper;@MockAnnouncementRepository announcementRepository;@InjectMocks@SpyAnnouncementManagerImpl announcementManagerImpl = new AnnouncementManagerImpl();@Beforepublic void before() {List<Announcement> res = new ArrayList<>();Announcement announcement = new Announcement();announcement.setId("dsfsdf");announcement.setAnnouncementContent("dsfbuiashf");res.add(announcement);PowerMockito.when(announcementMapper.queryByParams(Mockito.any(QueryWrapper.class), Mockito.any(Page.class))).thenReturn(res);PowerMockito.when(announcementMapper.selectCountByParams(Mockito.any(QueryWrapper.class))).thenReturn(1l);}@Testpublic void save() {}@Testpublic void findByPage() {QueryParams<AnnouncementDTO> params = new QueryParams<>();params.setPage(new Page(1,10));List<SortInfo> sort = new ArrayList<>();params.setSortInfo(sort);List<InputField> fields = new ArrayList<>();params.setParams(fields);IPage<Announcement> page = announcementManagerImpl.findByPage(params);Assert.assertNotNull(page.getTotal());Assert.assertNotNull(page.getRecords());}
}
从上面代码可以看出,被@Mock修饰后的变量announcementMapper则会产生一个AnnouncementMapper的mock类,不用@mock注解用mock方法来产生一个announcementMapper是一样的效果。
@InjectMocks注解
@RunWith(PowerMockRunner.class)
public class AnnouncementManagerImplTest {@MockAnnouncementMapper announcementMapper;@MockAnnouncementRepository announcementRepository;@InjectMocks@SpyAnnouncementManagerImpl announcementManagerImpl = new AnnouncementManagerImpl();@Beforepublic void before() {List<Announcement> res = new ArrayList<>();Announcement announcement = new Announcement();announcement.setId("dsfsdf");announcement.setAnnouncementContent("dsfbuiashf");res.add(announcement);PowerMockito.when(announcementMapper.queryByParams(Mockito.any(QueryWrapper.class), Mockito.any(Page.class))).thenReturn(res);PowerMockito.when(announcementMapper.selectCountByParams(Mockito.any(QueryWrapper.class))).thenReturn(1l);}@Testpublic void save() {}@Testpublic void findByPage() {QueryParams<AnnouncementDTO> params = new QueryParams<>();params.setPage(new Page(1,10));List<SortInfo> sort = new ArrayList<>();params.setSortInfo(sort);List<InputField> fields = new ArrayList<>();params.setParams(fields);IPage<Announcement> page = announcementManagerImpl.findByPage(params);Assert.assertNotNull(page.getTotal());Assert.assertNotNull(page.getRecords());}
}
@InjectMocks注解修饰的类不能修饰抽象或接口类,被它修饰后,其被mock后的成员变量会注入
到@InjectMocks的类中。
比如上面的announcementMapper则会被注入到announcementManagerImpl中,当调用announcementManagerImpl时,原代码里的announcementMapper.selectCountByParams(queryWrapper)方法则会执行mock方法
调用PowerMockito.spy()方法
通过spy,Whilebox.setInternelState方法设置内部依赖
public class AnnouncementManagerImplTest {AnnouncementMapper announcementMapper;AnnouncementRepository announcementRepository;AnnouncementManagerImpl announcementManagerImpl;@Beforepublic void before() {MockitoAnnotations.openMocks(this);announcementManagerImpl = PowerMockito.spy(new AnnouncementManagerImpl());announcementMapper = PowerMockito.mock(AnnouncementMapper.class);Whitebox.setInternalState(announcementManagerImpl,"announcementMapper",announcementMapper);List<Announcement> res = new ArrayList<>();Announcement announcement = new Announcement();announcement.setId("dsfsdf");announcement.setAnnouncementContent("dsfbuiashf");res.add(announcement);PowerMockito.when(announcementMapper.queryByParams(Mockito.any(QueryWrapper.class), Mockito.any(Page.class))).thenReturn(res);PowerMockito.when(announcementMapper.selectCountByParams(Mockito.any(QueryWrapper.class))).thenReturn(1l);}@Testpublic void save() {}@Testpublic void findByPage() {QueryParams<AnnouncementDTO> params = new QueryParams<>();params.setPage(new Page(1,10));List<SortInfo> sort = new ArrayList<>();params.setSortInfo(sort);List<InputField> fields = new ArrayList<>();params.setParams(fields);IPage<Announcement> page = announcementManagerImpl.findByPage(params);Assert.assertNotNull(page.getTotal());Assert.assertNotNull(page.getRecords());}
}
Mock使用方式或者技巧
在测试类上加注解@RunWith(PowerMockRunner.class)
等同于在@Before修饰的before方法中添加MockitoAnnotations.openMocks(this);
@Spy等同于PowerMockito.spy()方法
@Mock等同于PowerMockito.mock()方法
但是调用PowerMockito的方法时,必须要调用Whitebox.setInternalState()设置内部依赖
静态方法mockStatic
@RunWith(PowerMockRunner.class)
@PrepareForTest(IdUtils.class)
public class AnnouncementManagerImplTest {@MockAnnouncementMapper announcementMapper;@MockAnnouncementRepository announcementRepository;@InjectMocks@SpyAnnouncementManagerImpl announcementManagerImpl = new AnnouncementManagerImpl();@Beforepublic void before() {PowerMockito.mockStatic(IdUtils.class);List<Announcement> res = new ArrayList<>();Announcement announcement = new Announcement();announcement.setId("dsfsdf");announcement.setAnnouncementContent("dsfbuiashf");res.add(announcement);PowerMockito.when(IdUtils.randomUUID()).thenReturn("sahduiashdi");PowerMockito.when(announcementMapper.queryByParams(Mockito.any(QueryWrapper.class), Mockito.any(Page.class))).thenReturn(res);PowerMockito.when(announcementMapper.selectCountByParams(Mockito.any(QueryWrapper.class))).thenReturn(1l);}@Testpublic void save() {}@Testpublic void findByPage() {QueryParams<AnnouncementDTO> params = new QueryParams<>();params.setPage(new Page(1,10));List<SortInfo> sort = new ArrayList<>();params.setSortInfo(sort);List<InputField> fields = new ArrayList<>();params.setParams(fields);IPage<Announcement> page = announcementManagerImpl.findByPage(params);Assert.assertNotNull(page.getTotal());Assert.assertNotNull(page.getRecords());}
}
当需要mock静态方法的时候,必须要加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是静态方法所在的类。
添加完注解再使用PowerMockito.mockStatic()方法,mock静态类。
@PrepareForTest的使用场景
当使用PowerMockito.whenNew方法时,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是需要mock的new对象代码所在的类。
当需要mock final方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是final方法所在的类。
当需要mock静态方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是静态方法所在的类。
当需要mock私有方法的时候, 只是需要加注解@PrepareForTest,注解里写的类是私有方法所在的类
当需要mock系统类的静态方法的时候,必须加注解@PrepareForTest和@RunWith。注解里写的类是需要调用系统方法所在的类
阻止代码初始化,包括static{}静态代码块或者static变量的初始化
@SuppressStaticInitializationFor("cn.com.jc.utils.IdUtils")
3.3、问题
1、使用@InjectMocks修饰接口类报错
解决方法:
①收到new一个实现类的对象
@InjectMocksAnnouncementManager announcementManager = new AnnouncementManagerImpl();
②可以在@Before修饰的before()方法中添加spy方法注入该实现类对象
@InjectMocksAnnouncementManagerImpl announcementManager;@Beforepublic void before() {announcementManager = PowerMockito.spy(new AnnouncementManagerImpl());}
java单元测试之mock篇相关推荐
- Java单元测试之Mock框架
一.引言 二.为什么要用Mock 三.Mock使用场景 四.Mock定义 五.Mock框架 五.Mockito 5.1 Mockito基本使用 5.2 MockMVC测试 5.2.1 初始化MockM ...
- java单元测试之Mock测试编写
mock框架官方文档地址:https://javadoc.io/static/org.mockito/mockito-core/3.2.0/org/mockito/Mockito.html#verif ...
- Java单元测试之模拟利器-使用PowerMock进行Mock测试
首页 国产Linux Linux命令 openSUSE ArchLinux Slackware FreeBSD Ubuntu CentOS Fedora Debian PHP教程 在线教程 登录 注册 ...
- Java单元测试之JUnit4详解
2019独角兽企业重金招聘Python工程师标准>>> Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @B ...
- Java基础学习总结(24)——Java单元测试之JUnit4详解
Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @BeforeClass 全局只会执行一次,而且是第一个运行 @Before ...
- 单元测试之mock使用
目录 一.简介 二.使用mock做单元测试的优点 1.效率高 2.TDD(测试驱动开发) 3.并行开发 4.解决环境依赖问题 三.mock实现原理 四.mock使用 1.导入Maven依赖包 2.编写 ...
- SpringBoot单元测试之mock静态方法
The article summary 1 为什么要对静态方法mock 2 如何使用`powermock`对静态方法`mock` 2.1 添加依赖 2.2 编写测试类 2.3 需要注意的问题 1 为什 ...
- 《Pragmatic Unit Testing In Java with JUnit》—单元测试之道读后感
<Pragmatic Unit Testing In Java with JUnit> ...
- java单元测试总结
java单元测试(使用junit) http://www.cnblogs.com/feiweiwei/archive/2009/06/16/1024623.html JUnit是由 Erich ...
最新文章
- c语言编号程序,c语言中如何在一个程序语句前加编号c语言中如何在一个程序语句前加...
- SQL Server 2005/2008 图形界面(SQL Server Management Studio Express)
- [SOJ] connect components in undirected graph
- 【LeetCode】0046.全排列 (递归详解)
- .Net解析html文档类库HtmlAgilityPack完整使用说明
- python3.9教程_Python3简明教程(九)—— 文件处理
- 机器学习中数据集的拆分
- java dll 乱码_java调用c++ dll出现中文乱码 | 学步园
- 关于php的函数,总结关于PHP文件函数有哪些
- 第12天--css三种定位及z-index
- 【数据预测】基于matlab双向长短时记忆BiLSTM(多输入单输出)数据预测【含Matlab源码 1826期】
- ubuntu下安装matlab及配置vot-toolkit
- nginx工作原理及配置
- 1.3-----Simplify 3D切片软件简单设置
- matlab 盲源信号分离,基于盲源分离的图像噪声滤除的研究(附Matlab仿真程序)☆
- @Value注入静态变量(static)
- androbench跑分性能排查
- 批处理判断操作系统的文件系统类型
- Unity 图片定点缩放功能
- select查询之联合查询