一、为什么写单元测试
1.单元测试是什么
单元测试(Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。一个单元可能是单个程序、类、对象、方法等。
2.单元测试的意义
- 提高代码质量。我们写完单元测试,运行一把单元测试,找到不通过的地方,可以快速定位错误,并且寻找原因然后修改,大大减少调试时间,减少项目bug,从而提高代码质量。
- 方便重构。我们看完代码之后感觉代码很烂,然后想重构,又怕重构之后把代码改坏了。如果我们重构完了之后跑一遍单元测试,如果单元测试都通过,基本上重构的代码的逻辑是正确的。前提是单元测试代码覆盖率很高。
二、代码覆盖率
1.定义
代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。
2.常用的度量方式
(1)语句覆盖(StatementCoverage)
又称行覆盖(LineCoverage),段覆盖(SegmentCoverage),基本块覆盖(BasicBlockCoverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了,不考虑每个分支的组合。往往单独一行{}也被覆盖,语句覆盖常常被人指责为“最弱的覆盖”。
乍一看代码覆盖率达到了100%,并且通过了。但是,却没有发现当b=0时会抛出一个除零异常。所以不能只针对如何覆盖代码行编写测试,还要懂得其他的代码覆盖方式。
(2)判定覆盖(DecisionCoverage)
又称分支覆盖(BranchCoverage),所有边界覆盖(All-EdgesCoverage),基本路径覆盖(BasicPathCoverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到了。
判定覆盖测试时,只需要考虑判定结果为true和false时的两种情况
(3)条件覆盖(ConditionCoverage)
它度量判定中的每个子表达式结果true和false是否被测试到了。
条件覆盖测试时,需要考虑判定中的每个条件表达式的结果。但是,如果第一行为true,false;第二行为false,true时只走第一个分支,达不到100%覆盖。所以还有第四种覆盖方式。
(4)路径覆盖(PathCoverage)
又称断言覆盖(PredicateCoverage)。它度量了是否函数的每一个分支都被执行了。当有多个分支嵌套时,需要对多个分支进行排列组合。所以测试路径随着分支的数量指数级别增加。
三、单元测试运行缓慢
提交本地代码到测试环境,走流水线时单元测试运行时间过长,非常消耗服务器资源,借此问题延伸,做一些优化的探索。
1.搭建测试环境
2.运行单元测试
通过idea自带查看覆盖率的插件运行单元测试
可以看到在service层没有被注入的bean对象也被加载一次,以此推断出每运行一个单元测试类,所有的bean对象都被注入到容器中,从而导致了加载速度变慢。
3.优化方式
在@SpringBootTest中指定被加载的bean,可以看到在service中未被注入的bean没有被加载,由此可见,指定被加载的bean之后可以节省运行单元测试的大量时间和空间。