2017年12月31日做一次技术总结,人生第一次
框架选型:assertJ+Junit+powemockito+mockito+maven/ant/gradle+jacoco+jenkins+sonarqube
单元测试中,要测试目标模块的时候比如测试 service 方法的时候,service 方法中我们有可能会去调用数据库的执行结果,会取 redis 中缓存数据,也有可能会使用当前的系统时间,根据系统时间做一些逻辑处理,造成被测方法对外部有很强的依赖关系。假如被依赖的方法还没有开发完成或者预期输出有问题,就会造成被测方法单元测试失败。单元测试的思路就是我们在不涉及依赖关系的情况下测试代码。这种测试方式可以让你无视代码的依赖关系去测试代码的有效性,具体就是使用 mock 技术,模拟被依赖的组件的行为。
环境搭建:
1). 搭建 sonarqube+maven+jenkins
jenkins 加节点,随着 jenkins 构建项目的增多,单个项目构建时间从一分钟到十几分钟不等,当同时多个项目代码有提交更新触发构建的时候会有大量任务排队等待。
maven 配置文件,添加 sonar 的地址配置,执行 maven 构建后 sonar 会自行去进行静态代码扫描及单元测试分析
2). 项目中配置单元测试相关的东西
ant 构建:参见官网 http://www.jacoco.org/jacoco/trunk/doc/ant.htmldebug 模式,srccompile 和 testcompile 需要分开写;编译需要开启
maven 构建:添加 jacoco 插件、断言和 mock 相关 jar 包依赖配置
3)jenkins 添加构建项目
sonar 执行单测分析的时候会去默认的路径下面找 jacoco.exec.所以当你的项目自定义了 jacoco 生成 jacoco.exec 的路径的时候需要制定 jacoco.path
构建完成后 soanr 会统计出单元测试用例数,覆盖率,失败率等信息,具体的数据指标 sonar 数据库有一张单独的表每个字段对应一个指标,数据表中会对应每个指标字段有对应数据
代码编写:
a) 创建测试类
命名规则 *Test.java,测试方法的名称必须能描述清楚测试目的
b) 用例设计(最重要的部分)
单元测试不只是语句覆盖,分支覆盖,更多的应该从功能的角度去设计,100% 的语句全覆盖率并不代表 100% 的功能覆盖。单元测试的价值在于在进行减少功能测试阶段的 bug 数,从而减少版本迭代次数,提高效率。如果不能做到好的用例设计,只是单纯的为了覆盖而去覆盖意义不大。
c) 创建 mock 对象
d) mock 方法
方法中 new 对象;final 方法;静态方法;私有代码块;私有方法;系统类的静态和 final 方法;枚举类;spy;whitebox 测试私有方法;
e) mock 校验
f) junit 校验
使用 assertJ,校验强度要适中,不过度校验
参考资料
mock 使用参考:https://www.jianshu.com/p/77db26b4fb54
PowerMock 简单实现原理
当某个测试方法被注解@PrepareForTest标注以后,在运行测试用例时,会创建一个新的 org.powermock.core.classloader.MockClassLoader 实例,然后加载该测试用例使用到的类(系统类除外)。
PowerMock 会根据你的 mock 要求,去修改写在注解@PrepareForTest里的 class 文件(当前测试类会自动加入注解中),以满足特殊的 mock 需求。例如:去除 final 方法的 final 标识,在静态方法的最前面加入自己的虚拟实现等。
如果需要 mock 的是系统类的 final 方法和静态方法,PowerMock 不会直接修改系统类的 class 文件,而是修改调用系统类的 class 文件,以满足 mock 需求。
spring 使用的 runner 一般是 SpringJUnit4ClassRunner;当要使用 powermockRuner 的时候需要使用注解.@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
jacoco 可以通过远程监控的方式监控 tomcat 部署的项目;查看功能测试执行后的功能覆盖率情况;