分享在项目中进行单元测试的意义,执行和编写原则,为什么要使用 mock
chou403
/ UnitTest
/ c:
/ u:
/ 6 min read
什么是单元测试
单元测试又称为模块测试,是针对程序模块来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序,函数,过程等,对于面向对象编程,最小单元就是方法,包括基类,抽象类,或者派生中的方法。它是软件开发中的一种测试方法,通常由软件开发人员编写,用于测试他们正在开发的代码是否按照预期方法运行,主要目标是验证软件中最小的,可测试,独立的业务单元的正确性。
单元测试的意义
单元测试是产品质量控制左移的重要一环,它强调在软件开发生命周期的早期阶段就开始关注和提升质量,而不是等到产品开发完成后才进行质量检查。这种方法的目的是尽早的发现和解决问题,从而减少后期修复的成本和时间,提高最终产品的质量并降低项目风险。
单元测试的原则 AIR+FIRST(执行原则)
- A-Automatic(自动化) 单元测试应该是全自动执行的,无需人工干预
- F-Fast(快速的) 有单元测试应该是可以快速运行的,在各种测试方法中,单元测试的运行速度是最快的,大型项目的单元测试通常应该在几分钟内运行完毕,平均每个单侧用例执行不超过 60 毫秒。
- I-Independent(独立的) 单元测试应该是可以独立运行的,单元测试用例互相之间无依赖,且对外部资源也无任何依赖。比如,单元测试不可依赖不属于自己的数据,或者一些特定机器才有的环境变量,这些数据/变量需要 mock 进行隔离。
- R-Repeatable(可重复的) 单元测试应该可以稳定重复的运行,并且每次运行的结果都是稳定可靠的。
- S-SelfValidating(自我验证) 单元测试应该是用例自动进行验证的,不能依赖人工验证。
- T-Timely(及时的) 单元测试必须及时进行编写,更新和维护,以保证用例可以随着业务代码的变化动态的保障质量。
单元测试的原则 BCDE(测试用例编写原则)
编写单元测试代码遵守BCDE原则,以保证被测试模块的交付质量。
- B-Border: 边界值测试,包括循环边界,特殊取值,特殊时间点,数据顺序等。
- C-Correct: 正确的输入,并得到预期的结果。
- D-Design: 与设计文档相结合,来编写单元测试。
- E-Error: 强制错误信息输入(如: 非法数据,异常流程,非业务允许输入等),并得到预期的结果。测试的目标是验证代码的健壮性是否达到预期设计,所以不能只测试乐观路径,而是对乐观路径和悲观路径都进行测试。
覆盖率相关: 建议 80%,80%的百分比是单元测试成功的必要条件,但不是充分条件。
单元测试 mock 的重要性
什么是 mock
模拟对象的行为,达到屏蔽掉外部依赖的效果。 模拟一个方法的输入获得方法的输出。
单元测试为什么要 mock
- F-Fast(快速的): 单元测试可以快速运行
- I-Independent(独立的): 无依赖可以独立运行
- R-Repeatable(可重复的): 稳定重复运行,每次运行结果稳定可靠
单元测试常用注解
Junit
- @ExtendWith: 声明性的注册拓展
- @Test: 标识方法为一个测试用例
- @BeforeAll: 所有方法之前,执行一次
- @AfterAll: 所有方法之后,执行一次
- @AfterEach: 每个方法之执行
- @ParameterizedTest: 参数化测试方法
- @TimeOut: 设置超时时间
- @Order: 设置测试方法的执行顺序
- @RepeatedTest: 重复执行的次数
- @Disabled: 标识禁用的测试类和方法
- @DisplayName: 类或方法自定义显示名称
Mockito
- @Mock: 创建被 mock 的代理对象
- @Spy: 创建被 spy 的代理对象,可保留原对象的行为
- @InjectMocks: 创建真实对象,常用于被测试类,可注入 mock 对象
- @Captor: 用于捕获方法调用的参数,方便进一步的断言和校验
- @MockitoSettings: 用于设置 Mockito 框架的全局设置
SpringBoot
- @MockBean: 创建被 Spring 管理的 mock bean,常用于集成测试中
- @SpyBean: 创建被 Spring 管理的 spy bean,常用于集成测试中