【单元测试】基础理论

https://insights.thoughtworks.cn/practical-test-pyramid/

https://developer.aliyun.com/article/792515  Java编程技巧之单元测试用例编写流程

https://developer.51cto.com/article/708764.html  淘系用户平台技术团队单元测试建设

https://martinfowler.com/articles/mocksArentStubs.html

https://www.baeldung.com/mockito-series

 

阿里系列文章 

5个关键问题让单元测试的价值最大化
https://zhuanlan.zhihu.com/p/649220598
Java编程技巧之单元测试用例编写流程
https://developer.aliyun.com/article/783992
如何写出有效的单元测试
https://developer.aliyun.com/article/1002205
5个编写技巧,有效提高单元测试实践
https://developer.aliyun.com/article/1081898
阿里是如何进行单元测试培训的?(附回放视频)
https://mp.weixin.qq.com/s/wzGxqNv58Zig9_Izi3VhDg
那些年,我们写过的无效单元测试
https://mp.weixin.qq.com/s/R4ZKWcB4TMFAiQlnIRqNeQJava单元测试技巧之JSON序列化

单元测试技巧之JSON序列化
https://developer.aliyun.com/article/796000


 

 

 好单元测试的几个要点

摘自阿里巴巴开发规约:

l  单元测试必须遵守AIR原则,单元测试必须具备Automatic(自动化),Independent(独立性),Repeatable(可重复)性;

l  单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试;

l  单元测试要保证测试粒度足够小。单元测试测试粒度足够小,有助于精确定位问题。单测粒度至多是类级别,一般是方法级别;

l  单元测试要遵守BCDE原则,Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等;Correct,正确的输入,并得到预期的结果;Design,与设计文档相结合,来编写单元测试;Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果;

l  核心业务、核心应用、核心模块的增量代码要确保单元测试通过;

 

单元测试编码范式

这里主要以Mockito单元测试框架为模版

l  Mock :通过when().thenReturn/thenAnswer/thenThrow 或者doReturn().when()等mock方式将依赖类方法进行模拟,模拟服务依赖或者中间结果。

l  DO : 调用被测试类方法,执行测试链路。

l  Verify : 校验执行结果正确性,通过Assert校验数据结果准确,通过Verify校验链路执行准确,通过expected=Exception.class校验异常链路。

 

单测要能报错

有些同学不喜欢用Assert,而喜欢在test case中写个System.out.println,人肉观察一下结果,确定结果是否正确。这种写法根本不是单测,原因是即使当时被测试代码是正确的,后续这些代码还有可能被修改,而一旦这些代码被改错了。println根本不会报错,测试正常通过只会带来虚假的自信心,这种所谓的"单测"连暴露错误的作用都起不到,根本就不应该存在。

 

单测要有覆盖度(SUT)

IDEA支持覆盖度度量

强度是指单元测试中对结果的验证要全面,覆盖度则是指测试用例本身的设计要覆盖被测试程序(SUT, Sysem Under Test)尽可能多的逻辑。只有覆盖度和强度都比较高才能较好的实现单测的目的。

按照测试理论,SUT的覆盖度分为方法覆盖度,行覆盖度,分支覆盖度和组合分支覆盖度几类。不同的系统对单测覆盖度的要求不尽相同,但这是有底线的。一般来说,程序配套的 单测至少要达到>80%的方法覆盖以及>60%的行覆盖 ,才能起到"看门狗"的作用,也才是有维护价值的单测。

等价类划分可以帮助我们用更少的测试代码写出更高覆盖度的单测。 单元测试是典型的白盒测试 ,等价类的划分以及单元测试的编写最好都由SUT的编写者自己去完成,这样整体效率最高。

 

测试规则

  • FIRST

Fast:快速;测试执行越快越早发现问题

Isolated:独立,每个用例独立,没有依赖,从而可以并行甚至分布式执行;

Repeatable:可重复,每个用例不管执行多少次,执行结果一致,幂等;比如用例跟时间相关,可能结果不幂等。

Self-validation:自验证,测试用例必须告知断言结果,而不是人工判断,比如通过println打印。

Timely:及时,不要拖延

  • Right-BICEP

Right: 是否符合测试要求,验证待测试系统是否满足设计要求

Boundary:是否检测了所有边界行为

Inverse:是否需要反向检查,

Cross-checking:交叉检查,通过另一种方法对结果进行检查,比如需求的另一个解决方案

Error: 是否需要检查异常情况;如果异常是需要关注的,则需要覆盖异常路径;

Performance:是否需要检查性能,

  • CORRECT

Conformance:运行结果是否符合预期的规则

Ordering:值是否应该有序或无序

Range:结果在给定范围内是否符合预期

Reference:待测系统SUT是否正确引用了所依赖组件DOC

Existence:待测系统是否因关键要素存在性被影响,0-1-N问题

Cardinality:某些数值计算是否超出预期,如下标越界

Time:与时间相关的问题是否需要测试,比如耗时,并发问题

 

评估单元测试覆盖率

 

http://xunitpatterns.com/Test%20Double.html

  

 

 A stub has no logic, and only returns what you tell it to return.

A mock has expectations about the way it should be called, and a test should fail if it’s not called that way. Mocks are used to test interactions between objects, and are useful in cases where there are no other visible state changes or return results that you can verify (e.g. if your code reads from disk and you want to ensure that it doesn't do more than one disk read, you can use a mock to verify that the method that does the read is only called once).

A fake doesn’t use a mocking framework: it’s a lightweight implementation of an API that behaves like the real implementation, but isn't suitable for production

posted @ 2022-12-31 21:06  飞翔在天  阅读(67)  评论(0编辑  收藏  举报