写单元测试的小体会
·
之前一直不太理解单元测试的作用,也没有写过太多的单元测试,最近做了一个抽奖项目,写单元测试的时候发现自己对这一块了解太少了,所以借着这次机会对 单元测试进行了实践。
基本问题
1. 测试什么
我理解单元测试是主要针对某个方法,如果几个方法是解决了一个问题,也可以针对几个方法,但是这样的话,其实方法写的是有问题的,要遵守单一职责的原则。
单元测试的第一个重点:测试一个方法(如果非非非常必要,可以多个)
2. 什么期望
测试某个方法如果给定确定的输入,会不会产生预期的输出。比如一个转换大小写的方法,输入a,那么预期输出就是A。
单元测试的第二个重点:明确自己的期望,知道自己要测试那些问题
3.如何处理依赖问题
一个正常的单元测试,首先就是要有Mock的数据,然后需要Mock方法中的依赖输出,最后才是看是不是方法允许是不是符合预期。我的理解是,测试的方法调用其它方法应该通过Mock的方式,只需要模拟各种返回值。
单元测试的第三个重点:Mock测试方法中调用的其他方法,注意不论是远程还是本地的依赖方法,都应该通过Mock的方式。这些依赖的方法,同样需要使用单元测试保证运行复合预期。
4.如何进行
- 如果是私有方法,通过反射的方式测试
- 如果是公共方法, 直接调用
5.有什么用
- 测试代码,废话。。。
- 代码变更后,可以跑下测试,看看是否还符合自己的预期
如果每个方法的单元测试都是符合我们预期的,那么整合起来会有问题??
如果真的会出现问题,可能要从业务的角度去多考虑,因为每个方法都符合了预期,当然也可能是单元测试没有考虑到某个问题,导致单元测试不全面
什么时候写
- 很多地方都说单元测试要在撸码之前写,我觉得确实这样,但是要考虑几个因素:
- 如果要在开发之前写,那么一定要做好设计,每个方法的输入和输出都要考虑到,这还是挺有挑战性的。并且还要有最基本的方法流程。
- 目前来说,前后端分离,会进行同步开发,所以如果一开始就写单元测试,肯定会推迟联合调试的时间,对一个快速开发的团队来说,后台压力会比较大
- 一边写方法,一边写单元测试
没有尝试过这种,暂时没有感受,但是如果写完一个方法就去写测试,接着写另外的方法。这样看来,还不错,不会因为自己的方法,导致团队的开发出现阻塞(自己的方法被队友调用)。 - 全部撸完再写
本次就是这种方法,开发下来最多的感受是,写单元测试的过程中发现BUG,需要修改代。。。。
未解决的问题
- 单元测试的方法,调用同类的方法如何Mock
- 私有方法的测试,如何捕获异常
遵循的原则
- 一定要写单元测试
- 架构能力强,可以之前写;一边开发,一边写,会简单一些
- 记住自己要测试的只是当前方法的行为,不相关的依赖方法Mock,这些依赖方法会有自己的测试方法
- 改完代码,跑一遍单元测试
让一个程序员明确的知道,自己的方法不会有问题
如何写
/**
* 获取奖品
* 期望1:如果有一般奖品获得奖品
* 期望2:如果没有一般奖品,2.1获取默认奖品 2.2:返回没有奖品
* 期望3:如果奖品数量为0或小于0返回Optional.Empty()
*/
@Test
public void getAwardTest() {
final int defaultTotalNum = 100;
final int zero = 0;
//这里是Mock数据
when(drugsGenerateService.getTotalNum())
.thenReturn(defaultTotalNum)
.thenReturn(defaultTotalNum)
.thenReturn(zero);
when(drugsGenerateService.getAllAwards())
.thenReturn(getTestAwards())
.thenReturn(new ArrayList<>());
final int defaultAwardNum = 100;
AwardDTO defaultAward = AwardDTO.builder()
.isDefault(true)
.desc("默认奖品")
.num(defaultAwardNum).build();
when(drugsGenerateService.getDefaultAward())
.thenReturn(Optional.of(defaultAward))
.thenReturn(Optional.empty());
//期望1:如果有一般奖品获得奖品
Optional<AwardDTO> awardOptional = drugsLotteryDrawService.getAward();
Assert.assertTrue(awardOptional.isPresent());
Assert.assertTrue(!awardOptional.get().getIsDefault());
//期望2.1 获取默认奖品
Optional<AwardDTO> awardOptional2 = drugsLotteryDrawService.getAward();
Assert.assertTrue(awardOptional2.isPresent());
Assert.assertTrue(awardOptional2.get().getIsDefault());
//期望2.2:返回没有奖品
Optional<AwardDTO> awardOptional3 = drugsLotteryDrawService.getAward();
Assert.assertTrue(!awardOptional3.isPresent());
//期望3:如果奖品数量为0或小于0返回Optional.Empty()
Optional<AwardDTO> awardOptional4 = drugsLotteryDrawService.getAward();
Assert.assertTrue(!awardOptional4.isPresent());
}
- 一开始要明确自己的期望
- Mock需要的数据
Mock工具 - 验证自己的期望
哪些需要写
- 逻辑复杂的方法
- 逻辑简单,但是会频繁改动(方法改动很容易影响单元测试的期望)
更多推荐
所有评论(0)