最近在学习单元测试,除了学习框架外,还动手写了些业务测试。 现在再回头看 clean code 这本书这一章,与刚开始看时似懂非懂的感觉完全不同。 纸上得来终觉浅,绝知此事要躬行
9.1 TDD 的三定律
中文翻译看得有点费力,感觉有点绕:
- 在编写不能通过的单元测试前,不可编写生产代码 - 只可编写刚好无法通过的单元测试,不能编译也算不通过 - 只可编写刚好足以通过当前失败测试的生产代码
找找英文原文: The three laws of TDD - You may not write production code until you have written a failing unit test. - You may not write more of a unit test than is sufficient to fail, and not compiling is failing. - You may not write more production code than is sufficient to pass the currently failing test.
- 在写出符合生产环境标准的代码前,你会先写出通过不了单测用例(后面统一用
单测
表示单元测试
)的代码。 - 在写出会导致无法通过的单测用例前,你会先写出无法通过编译的代码。
- 在写出符合生产环境代码之前,你要先写出只能通过当前单测用例的代码。
以上三个定律,其实说的是我们会花大量的时间来写出正确的单测代码,原书的翻译完全不知所云..
这三条定律每30秒循环一次,测试代码与生产代码一起编写,测试代码只比生产代码提前几秒。 按这样的规则来写代码,最终测试代码量足以匹敌生产代码代码量,如此会有管理问题
9.2 如何管理(原子标题:保持测试整洁)
怎么管理,原书标题已经说得很明白,保持测试代码整洁。 - 对待测试代码和对待正式代码一样认真。思考,设计,仔细维护。 - 脏单测至少等同于没单测(也许不会比无测试更糟糕) 因为单测代码修改的频率与生产代码是相同的。 - 如果单测代码不干净,那修改生产代码将会遇到障碍
9.3 什么样的单测是整洁的
- 单测代码拆分为三部分:Build Operation Check 或 Given When Then : 给写某些数据,执行某个操作,应该得到某些结果
- 单测代码与生产代码有时需要使用不同的标准,举的例子是性能(单测中为可读性考虑可使用 String + 操作,而不使用 StringBuffer)
9.4 具体怎么写单测?(原子标题:每个测试一个断言)
- 作者倾向同意:一个测试验证一个概念,一个概念使用尽量少的断言
- 利用模板方法模式(Template Method)消除重复的 given/when。
第一点深有体会,如果一个测试限定只写一个 assert ,那会有大量的重复代码,继而产生维护成本。 比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test fun testCombineConfig(){
// given
val configsAssertUseFirst = mapOf(
Config(1) to Config(2),
Config(0) to null,
....
)
configAssertUseFirst.map{
val first = it.key
val second = it.value
//when
val result = Updater.combileConfig(first,second)
// then
assertEquals(first,result)
}
}
以上代码如果按某些规则约束,只写一个 assert ,那将是大量结构类似的 testCombileXXX
方法。 不过目前我的这个写法是把asset 放到 for 循环内,不知是否有问题,待验证。
F.I.R.S.T 原则
Fast/Independent/Repeatable/Self-Validating/Timely