TDD

Abstract

Test Driven Developement

Category

learning note

Authors

Walter Fan

Status

WIP as draft

Updated

2024-05-04

1. 背景

1. 测试的时机

不是东西做出来再测,而是测好了东西才能出来 各个大小公司,独立的测试团队都在削减人员,不是测试不重要,而是需要全员从一开始就要做测试, 全过程测试, 早期注重单元测试和组件测试, 后期注重集成测试和端到端测试。在一个迭代尽量做一个相对完整的功能, 及时做集成, 而不是最后再一起做集成测试 (当然独立专业的测试团队还是很有必要的, 自己测自己写的东西, 很难发现意想不到的问题)

2. 测试的效率

讲究有效性,稳定性和性能,一定要自动化,跨越多个组件的端到端测试必须有,可是不宜多,而且应该是聚焦在于功能性,无需过度测试,有必要才测, 代码对测试友好, 也就是易于测试。 测试要讲究有效性,稳定性和性能。 从思维定势的角度来看, 单元测试可以自己做, 组件测试和集成测试最好换位思考, 结对测试或交由测试专家来做

3. 测试的度量

测试要有覆盖率,哪怕仅作参考 性能测试更要有数据,比如 CPS TPS QPS 最耗时间的函数等在测试过程中收集到的度量数据

4. 测试的对象

测试到底测什么? 测试目的要明确, 检查点是先定义好. 哪些值, 状态, 还是行为要检查? 测试范围更要定义清楚, 单元,组件,系统内部还是端到端的用户操作?

测试的分类

  • 黑盒测试

  • 白盒测试

— - 手工测试 - 自动测试

— - 冒烟测试 - 回归测试 - 探索性测试

— - 单元测试 - 组件测试 - 消费者测试 - 集成测试 - 端到端测试

— - 压力测试 - 异常测试

测试金字塔

![](test_pyramid.png)

因为越往上测试的实现和维护成本就越高, 测试速度也越慢, 所以提倡多写单元测试, 少写端到端的测试, 少写不等于不写, 上层的测试着重测一些主要的路径, 不需要面面俱到, 不然费时费力

  • 层次越靠上,运行效率越低,延缓持续集成的构建-反馈循环。

  • 层次越靠上,开发复杂度越高,如果团队能力受限,交付进度受影响。

  • 端到端测试更容易遇到测试结果的不确定性。

  • 层次越靠下,单元隔离性越强,定位分析问题越容易。

为了提交效率,加快交付的频率和速度,使产品具备随时可发布的能力,我们需要构建自动化的测试 - 单元测试 - 集成测试(包括 API 测试) - 端到端的功能测试

单元测试的原则

有本书单元测试之道总结了若干单元测试的原则, 先来回顾一下 Pragmatic Unit Testing by Andrew Hunt and David Thomas

FIRST 原则

  • Fast 快速的

  • Isolated 隔离

  • Repeatable 可重复

  • Self-Validating 自验证

  • Timely 及时的

Right-BICEP 测试原则

  • Right - Are the results right? 结果是否正确?

  • B - are all the boundary conditions correct? 所有的边界条件测试结果正确吗

  • I - can you check the inverse relationships? 有没有检查反向关系

  • C - can you cross-check results using other means? 能不能用其他方法交叉检查结果?

  • E - can you force error conditions to happen? 能不能强制错误情况发生?

  • P - are performance characteristics within bounds? 性能特性在不在允许范围之内?

CORRECT 检查原则

  • C - Conformance - does the value conform to an expected format? 一致性 - 值是否符合预期的格式?

  • O - Ordering - is the set of values ordered or unordered as appropriate? 排序 - 值的集合是否根据需要进行排序或无序?

  • R - Range - is the value within reasonable minimum and maximum values? 范围 - 值是否在合理的最小值和最大值范围之内?

  • R - Reference - does the code reference anything external that isn’t under direct control of the code itself? 引用 - 代码是否引用了不受代码本身直接控制的外部依赖?

  • E - Existence - does the value exist (e.g. is not null, non-zero, present in a set)? 存在 - 值是否存在(例如,不为null,非零,是否存在于集合中)?

  • C - Cardinality - are there exactly enough values? 基数 - 是否有足够的值?

  • T - Time (absolute and relative) - is everything happening in order? At the right time? In time? 时间(绝对和相对) - 一切事件是否有序? 是否在正确的时间? 是否及时?

测试相关框架与库

林林总总, 不胜枚举, C++的googletest, gmock, Java的 Junit, TestNG, Mockito, PowerMock, JavaScript 的 Qunit, Python 的 unittest, Lua 的 luaunit, 等等, 其实他们都是脱胎于 JUnit , 使用起来也是大同小异。

测试的策略

测试要分类,分组,而且要能快速定位和诊断测试的失败之处 在开始系统级测试之前, 最好能列一个测试矩阵 Test matrix 把所有已知条件, 场景和输入, 或变化的因子列出来, 以免遗漏, 例如我们要测试网页的登录功能对于各大浏览器的兼容性:

Components Scenario Safari Edge Chrome Firefox Opera Portal Login pass pass pass pass pass

测试用例的组织

Given-When-Then === ==== ==== BDD 说明 示例 === ==== ==== Given 先决条件 广告部定制了企业的服务电话语音为最近一次促销活动广告 When 行为或事件 用户拔打 800 服务电话 Then 期待的变化或结果 欢迎声后听到最近一次促销广告 === ==== ====

测试的过程

测试四步法 1. Setup 2. Exercise 3. Verify 4. Teardown

![](test_steps.png)