版本:v1.8
测试原则
我们一般认为有这三种测试类型:
- 单元测试(Unit test)
- 集成测试(Integration test ,在测试的过程中会 mock API )
- 端到端测试(End-to-End test, e2e test)
它们各有优缺,为获得更好的开发体验,我们在编写测试时应当遵守以下原则。
我们编写和维护单元测试的主要目的是:
- 外在目的:保证函数的功能符合设计预期
- 内在目的:促进编码者使用更合理的代码结构和面向接口编程
单元测试的测试对象是一个类或者是一段算法代码。理论上来说,有着较为独立逻辑的函数应该至少拥有一个单元测试(不包括 getter 和 setter )。
编写单元测试的基本原则如下:
- 大道至简(Keep It Simple and Stupid)
- 一个用例只覆盖一个场景
- Mock 工具(例如
golang/mock
)虽然很强大,但是我们并不推荐使用。当你觉得在单元测试中需要使用 Mock 工具,那么你真正要做是集成测试甚至端到端测试。
单个测试需要保证高效率,例如在重构代码的过程中,一旦你修改了一处函数逻辑,这将会触发整个模块的单元测试以保证这些修改符合预期。
集成测试将组装系统中部分高度关联的模块,并测试模块间的交互是否符合预期。
例如 KubeVela 中的集成测试主要分为两类:
- 对于 vela core 控制器来说,你需要为主要流程添加对应的测试,例如渲染 (render)、编排 (orchestrate) 和将 CRD 部署到 Kubernetes 的过程。在这种情况下,一般会使用 mock 服务器来 mock Kubernetes 的 API ,这你就能在不使用真正的 Kubernetes 集群和 CRD 控制器的情况下编写覆盖这些自动化流程的测试了。
- 对于 addon 来说(例如 VelaUX、apiserver 和 vela cli )你可以添加与创建、摧毁和更新 Application 相对应的集成测试,而不需要运行一整个控制器。
Vela core 部分的集成测试并不关心 CRD 是否在工作,因此它能够通过 mock CRD 控制器的行为来提高测试效率。而外部 CLI 部分的测试不关心 Application 的动作,它只需要保证新的 Application 的 spec 正确即可。
端到端测试的目的是模拟真实用户的行为,用以验证整个项目。
对于下列情况,我们建议使用端到端测试:
- 与上游或下游项目交互,例如:
- 进行渐进式部署的过程中 Application 控制器需要与 rollout workload 交互
- 在同一个命令中,CLI 依赖控制器的回应以进行下一步操作
- 核心功能或核心场景:每个核心功能或场景必须至少有一个端到端测试
测试的目的是保证软件持续交付的质量,重点在于“持续”。我们不仅要确保当前交付的质量,还要确保未来软件交付的质量。发挥好三种测试类型各自的优势,将它们结合起来,保证软件的整体质量是尤为重要的。
时间消耗 | 测试稳定性 | 能否模拟用户行为 | |
---|---|---|---|
单元测试 | 少 | 高 | 否 |
集成测试 | 中 | 中 | 基本能 |
端到端测试 | 多 | 低 | 能 |
运行所消耗的时间在这里很容易理解。单项测试所涵盖的软件功能规模越大,环境准备和测试运行所花费的时间就越多,这就导致测试效率也降低了。 在稳定性方面,测试覆盖率越高,它可能遇到的问题就越多,而且有些问题并不是我们想要发现的真正的错误(只是噪声而已),这就导致测试稳定性降低了。对于模拟真实用户行为,只有端到端测试可以覆盖端到端,保证整个链路可以协同工作。
至于长期价值,是指现有测试在持续的软件迭代过程中的价值。对于单元测试,在代码重构时会根据类和函数的变化进行调整。 因此,代码库将会与软件迭代中的热点保持一致并不断发展。
但是集成测试或端到端测试通常被拆分为子系统边界,其外部接口相对稳定(分布式系统软件迭代过程中很少有功能变化,一般是为了前向兼容)。而且集成测试或端到端测试的代码库相对稳定,这对系统未来的演进非常重要,这样才能及时发现新功能是否损坏了现有功能。
结合三者的特点,最好的平衡方式就是遵从金字塔模型: 底部是单元测试,中间是集成测试,最上层是端到端测试。
\
/ \
/ \
/ \
/ e2e \ (端到端测试)
/---------\
/ \
/ integration \ (集成测试)
/ \
/-----------------\
/ \
/ unit-test \(单元测试)
/ \
---------------------------
我们希望你在 KubeVela 项目中遵循 70/20/10 原则,即 70% 的单元测试、20% 的集成测试和 10% 的端到端测试。尽管每个模块有所差异,但是一般层级越高,测试覆盖率越大,测试用例越小。为了遵守金字塔模型,你需要避免以下几种情况:
- 倒金字塔,全靠端到端测试
- 沙漏模型,大量的单元测试和端到端测试,但没有集成测试
由于我们目前主要关注功能而无暇顾及测试稳定性,这使得我们很难维持测试的质量。但对于我们所有的 maintainer 来说,我们有责任追求高质量的测试,这样才能确保社区长期良好发展。
Last updated on 2023年5月6日 by Tianxin Dong