文章目录

  • 目前开发中,单元测试遇到的问题
  • 解决方案--Mock
    • Junit4 + Mockito:
    • Mockito常用注解:
    • Mockito常用方法:
    • Tips:
  • 总结

目前开发中,单元测试遇到的问题

在业务代码开发完成以后,需要对新增代码进行单元测试,由于项目依赖的第三方组件以及外部系统接口较多,每次执行单元测试时都需要启动整个项目,加载各种依赖,而且由于网络限制有时还需要申请各种ACL,且项目启动耗时较长,有时仅仅为了跑一个仅有几行代码的单元测试,却要耗时几分钟等待项目的启动,严重违背单元测试的初衷。这种情况导致了大家写单元测试的积极性不高,甚至直接跳过单元测试,直接把代码发布到测试环境进行集成测试。

解决方案–Mock

上述问题有没有解决方案呐,答案是肯定是有的,那就是Mock,对外部依赖进行mock,仅执行自己的代码。目前mock的工具有很多,像PowerMock,EasyMock,Mockito等。下面针对Mockito的使用方法做一个简单的介绍

Junit4 + Mockito:

先来看一个例子:

@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserInfoMapper userInfoMapper;@Resourceprivate WhiteListCheckService whiteListCheckService;@Resourceprivate UserLevelRemoteProxy userLevelRemoteProxy;@Overridepublic UserInfoBo queryUserInfo(String userId){UserInfoEntity userInfo = userInfoMapper.findById(userId);boolean isWhiteListUser = whiteListCheckService.isWhiteListUser(userId);String userLevel = userLevelRemoteProxy.queryUserLevelById(userId);UserInfoBo userInfoBo = BeanUtils.copy(UserInfoBo.class, userInfo);userInfoBo.setUserLevel(userLevel);userInfoBo.isWhiteListUser(isWhiteListUser);return userInfoBo;}
}

上面是一个常用类型的service方法,只是省略了一些业务逻辑,方法中会调用mapper方法查询数据库,系统内部其他service方法,还有外部接口.现在我们使用Junit4+Mockito来对该方法进行单元测试:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest{@InjectMocksprivate UserServiceImpl userService;@Mockprivate UserInfoMapper userInfoMapper;@Mockprivate UserLevelRemoteProxy userLevelRemoteProxy;@Testpublic void queryUserInfoTest(){UserInfoEntity userInfo = Mockito.mock(UserInfoEntity.class);Mockito.when(whiteListCheckService.isWhiteListUser(Mockito.anyString)).thenReturn(true);Mockito.when(userInfoMapper.findById(Mockito.anyString())).thenReturn(userInfo);Mockito.when(userLevelRemoteProxy.queryUserLevelById(Mockito.anyString())).thenReturn("12Lev");UserInfoBo userInfoBo = userService.queryUserInfo("123");Assert.assertEquals("12Lev", userInfoBo.getUserLevel());}
}

执行上述方法,会在执行userInfoMapper.findById方法时,返回我们mock的UserInfoEntity的实例,当执行whiteListCheckService.isWhiteListUser方法时,会返回true,执行userLevelRemoteProxy.queryUserLevelById方法时,会返回12Lev。我们在把依赖的接口进行Mock以后,就可以在不启动项目的前提下执行该单元测试了,进而提高了单元测试的执行速度。同时也可以对代码里的不同分支编写多个单元测试,进一步提升代码的单元测试覆盖率。

Mockito常用注解:
  • @Mock :创建一个Mock实例
  • @InjectMocks :会把@Mock@Spy注解的对象自动注入进来,一般用于创建需要被测试的对象实例
  • @Spy:允许创建部分模拟的对象
Mockito常用方法:
  • 参数匹配器:Mockito.anyString()/Mockito.anyInt()/Mockito.any()
  • 方法执行校验器:Mockito.verify()
  • 锚点方法调用及指定返回值:Mockito.when(mock.someMethod()).thenThrow(new RuntimeException).thenReturn("foo")
  • 执行真实实例方法:Mockito.spy()

更多方法请参考官方文档: https://javadoc.io/doc/org.mockito/mockito-core/latest/index-files/index-1.html

Tips:
  • Java 8 Lambda 匹配器的支持(Since 2.1.0):

    @Test
    public void testMethod(){List<String> list = Mockito.mock(List.class);list.add("111");list.add("222");list.add("333");Mockito.verify(list,Mockito.times(3)).add(Mockito.argThat(s -> s.length() <5));//list中最多被添加4个元素
    }
    
  • Mocking final type, enums and final methods (Since 2.1.0)

    Mockito从2.1.0版本开始支持对final type, enums and final methods进行mock,但是需要额外的配置,详情请参考: Mocking final types, enums and final methods

  • 对静态方法进行Mock(Since 3.4.0)

    需要把mockito-core依赖替换成mockito-inline,且对jdk版本有要求,若使用是jdk8或更早版本的,需要使用到ByteBuddy 依赖

            <dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>3.7.7</version><scope>test</scope></dependency><!-- 若使用的是jdk8或更早版本,需要添加如下依赖 --><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy</artifactId><version>1.12.1</version></dependency><!-- 若使用的是jdk8或更早版本,需要添加如下依赖 --><dependency><groupId>net.bytebuddy</groupId><artifactId>byte-buddy-agent</artifactId><version>1.12.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version></dependency>
    
       @Testpublic void mockStaticTest(){LocalDate yearOf2000 = LocalDate.of(2000, 1, 1);try (MockedStatic theMock = Mockito.mockStatic(LocalDate.class)) {theMock.when(LocalDate::now).thenReturn(yearOf2000);Assert.assertEquals(2000, LocalDate.now().getYear());}}
    
  • 对于私有方法的mock

    mockito是不支持对是由方法进行mock的,如果有这方面的需求,可以结合使用ProwerMock来做,至于mockito为什么不支持对私有方法进行mock,官方的说法如下:

    Mockito And Private Methods

总结

关于写单元测试,很多人认为是一件性价比不高的事情,与其花费大量时间对一些一眼就能看出执行结果的方法编写单元测试,还不如直接进行集成测试,跑一下主流程,没问题就可以提测了,但是这样做往往会忽略分支流程的测试覆盖,导致提测的代码质量不高,甚至会成为导致线上问题的隐患。所以,个人认为编写单元测试还是很有必要的,至少,要对新增代码进行单元测试覆盖。另外,现在有一些测试代码生成插件,可以帮助我们直接生成单元测试,大家感兴趣的话,可以尝试使用一下

TestMe

JCode5

Diffblue

参考

Mockito官网

360数科中间件团队博客中关于单元测试的文章

Mockito官方demo

单元测试Mock框架--Mockito相关推荐

  1. Mock和Java单元测试中的Mock框架Mockito介绍

    什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象.程序员通常创造模拟对象(mock object)来测试其他对象 ...

  2. android mock测试资源,Android 单元测试 --Mock 及 Mockito

    以前我在 Mock 概念 所谓的 Mock 就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,主要提供两大功能: 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等 指定这个 ...

  3. 单元测试mock框架——jmockit实战

    JMockit是google code上面的一个java单元测试mock项目,她很方便地让你对单元测试中的final类,静态方法,构造方法进行mock,功能强大.项目地址在:http://jmocki ...

  4. 【C#】【xUnit】【Moq】.NET单元测试Mock框架Moq初探!

    在TDD开发模型中,经常是在编码的同时进行单元测试的编写,由于现代软件开发不可能是一个人完成的工作,所以在定义好接口的时候我们就可以进行自己功能的开发(接口不能经常变更),而我们调用他人的功能时只需要 ...

  5. Mock框架Mockito入门教程

    在开发中,我们经常会依赖同事或者第三方提供的接口,如果该接口无法正常工作:比如接口正在修复,或者网络异常等.那么便会对需要依赖该接口的开发造成很大影响. 遇到这种情况,我们可能会想到模拟该接口以提供正 ...

  6. 单元测试mock之mockito使用

    先来一个简单的例子来感受一下 外部接口类:TestService.java 1 package com.yzl.mock; 2 3 /** 4 * 测试用服务 5 * 6 * @author yang ...

  7. 单元测试框架 Mockito 注解 – @Mock, @Spy, @Captor, @InjectMocks

    转载翻译自 https://howtodoinjava.com/mockito/mockito-annotations/ 这篇 mockito 的教程文章能够帮助你了解更多 mockito 注解,比如 ...

  8. 单元测试及框架简介 --junit、jmock、mockito、powermock的简单使用

    转 单元测试及框架简介 --junit.jmock.mockito.powermock的简单使用 2013年08月28日 14:33:06 luvinahlc 阅读数:6413 标签: 测试工具 单元 ...

  9. Mock框架的三次迭代,让你的单元测试更高效

    如何定义单元 对于单元测试中的单元,不同的人有不同的看法:可以理解为一个方法,可以理解为一个完整的接口实现,也可以理解为一个完整的功能模块或者是多个功能模块的一个耦合. 根据以往的单元测试经验,在设计 ...

最新文章

  1. Redis性能问题排查解决手册(值得收藏)
  2. 信息安全系统设计基础第七周学习总结
  3. WPF实现Android菜单动画
  4. 50: Luogu P4568 分层图
  5. svm分类器训练详细步骤_「五分钟机器学习」向量支持机SVM——学霸中的战斗机...
  6. Nodejs系列课程,从入门到进阶帮你打通全栈
  7. Python--SQLite学习(10.29)
  8. 怎么用python统计字数_Python 统计字数的思路详解
  9. python中文视频教程-中谷教育python中文视频教程(python视频教程) 完整版
  10. ViewPager使用讲解
  11. oracle用户权限管理
  12. 基于连接跟踪机制的状态防火墙的设计与实现
  13. 推荐一个Oracle数据库学习的网站
  14. 音响系统测试软件苹果,再谈汽车音响调试专用相位软件JL AUDIO Tools,苹果ios坛友的福音!|汽车数码...
  15. vue 引入第三方文件(高拍仪),传值及接口调用。
  16. global shutter和rolling shutter,全局快门与卷帘式快门
  17. android显示每一年所有日期的功能,Android获取本周所有日期
  18. 一个P9告诉你为什么某电商怕了拼多多
  19. 钟汉良日记:改变心态了,回武平待3年
  20. python文件重命名

热门文章

  1. GD32实战11__SPI FLASH
  2. 接地电阻测试仪的工作原理及技术指标
  3. 小数点怎么进行进制转换?
  4. Python--提高pip的下载速度
  5. asp.net 改变css,使用ASP.NET动态设置CSS值
  6. [入门篇]初识操作系统OS(这篇博客将帮你打开操作系统OS大门的第一步 超超超超超详细)
  7. git配置(SSH)
  8. 宁夏事业单位计算机类面试题,宁夏事业单位各地市面试都考什么?
  9. ncnn param文件及bin模型可视化解析
  10. iOS VideoToolbox 硬编指南