java 单元测试学习

单测的标准:

语句覆盖率达到70%;核心模块的语句覆盖率和分支覆盖率都要达到100%。 --- 《阿里巴巴Java开发手册》

单测覆盖度分级参考

Level1:正常流程可用,即一个函数在输入正确的参数时,会有正确的输出

Level2:异常流程可抛出逻辑异常,即输入参数有误时,不能抛出系统异常,而是用自己定义的逻辑异常通知上层调用代码其错误之处

Level3:极端情况和边界数据可用,对输入参数的边界情况也要单独测试,确保输出是正确有效的

Level4:所有分支、循环的逻辑走通,不能有任何流程是测试不到的

Level5:输出数据的所有字段验证,对有复杂数据结构的输出,确保每个字段都是正确的

60%左右的单测覆盖率可以非常轻松达到,但达到95%以上的覆盖率,需要覆盖各种代码分支和异常情况等,甚至是配置和bean的初始化方法,所投入的时间非常巨大,但边际效应递减。我想测试toString, getter/setter这样的方法也没有意义。多少合适,我认为没有一个固定的标准。高代码覆盖率百分比不表示成功,也不意味着高代码质量。该舍弃测试的部分就大胆的ignore掉。

1、隐藏的测试边界值

2、不要在springboot测试中使用@Transactional以及操作真实数据库

3、单测里时间相关的内容

笔者曾经在工作中遇到过一个极端case,一个CI平时都正常运行,有一次深夜发布, CI跑不过,后来经过第二天check才发现有前人在单测中取了当前时间,在业务逻辑中含有夜间逻辑(夜间消息不发),导致了CI无法通过。那么时间在单测中要如何处理呢?

在使用Mockito时,可以使用mock(Date.class)来模拟日期对象,然后使用when(date.getTime()).thenReturn(time)来设置日期对象的时间。

如果你使用了calendar.getInstance(),如何获取当前时间?Calendar.getInstance()是static方法,无法通过Mockito进行mock。需要引入powerMock,或者升级到mockito 4.x才能支持:

final类,static类等的单元测试

如第3点提到的calendar的例子,static类的mock需要mockito4.x的版本。否则就要引入powermock,powermock不兼容mockito3.x版本,不兼容mockito 4.x版本。由于老的应用引入了非常多的mockito3.x的版本,直接使用mockito4.x对final和static类进行mock需要排包。实践中看,JUnit、Mockito、Powermock三者之间的版本号有兼容性问题,可能会出现java.lang.NoSuchMethodError,需要根据实际的情况选择版本进行mock。

但是在新项目立项的时候,要确定好使用的mockito和junit版本,是否引入powermock等框架,确保环境稳定可用。老项目建议不要大规模改动mockito和powermock的版本,容易排包排到怀疑人生。

总结一下什么时候使用容器:

// 1. 使用PowerMockRunner

@RunWith(PowerMockRunner.class)

// 2.使用PandoraBootRunner, 启动pandora,使用tair,metaq等

@RunWith(PandoraBootRunner.class)

// 3. springboot启动,加入context上下文,可以直接获取bean

@SpringBootTest(classes = {TestApplication.class})

不要为了覆盖率测没意义的代码

比如toString,比如getter,setter,都是机器生成的代码,单测没意义。如果是为了整体测试覆盖率的提高,那么请在CI中排掉这部分包:

如何测试void方法

如果void方法内部造成了数据库的变更,比如insertPlan(Plan plan),并通过H2操作过数据库,那么可以验证数据库的条数变化等,校验void方法的正确性。

如果void方法调用了函数,可以通过verify验证方法得到调用次数:

userService.updateName(1L,"qiushuo");

verify(mockedUserRepository, times(1)).updateName(1L,"qiushuo");

如果void方法可能会造成抛出异常。

可以通过dothrow来 mock方法抛出的异常:

@Test(expected = InvalidParamException.class)

public void testUpdateNameThrowExceptionWhenIdNull() {

doThrow(new InvalidParamException())

.when(mockedUserRepository).updateName(null,anyString();

userService.updateName(null,"qiushuo");

}

使用 squaretest testme junit5 + Mockito

IDEA 安装 squaretest testme 插件

配置模板后 在你想要的生的单测的类 右键生成 test类

相关推荐
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹4 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫4 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石5 小时前
12/21java基础
java
李小白665 小时前
Spring MVC(上)
java·spring·mvc
sanguine__5 小时前
Web APIs学习 (操作DOM BOM)
学习
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea