jimmylv.github.io icon indicating copy to clipboard operation
jimmylv.github.io copied to clipboard

如何在遗留代码之上进行TDD?

Open JimmyLv opened this issue 6 years ago • 2 comments

GitHawk Upload by JimmyLv

只要业务在发展,系统调整就是必然,因为处理不同量级的系统本质上就不是一个物种。真正挑战的是,怎么在高速行驶中,把奥拓改成奥迪。

似乎这也是TDD的痛,tdd更适合从无到有0到1,那1->better 1怎么做呢?

先给遗留代码写测试,然后再放心大概重构吗?

  1. 根据业务功能写一个测试(AT)
  2. 运行测试,测试通过,绿
  3. 快速写一个新的实现(通常可以复制),测试通过,绿
  4. 重构新的实现,做进一步改进
  5. 替换原有的实现,运行测试,绿

但是,

补测试是个无底洞,因为一直在开发新功能。就好比今天吃昨天的剩饭,明天吃今天的剩饭 因为之前的代码在编写时没有考虑可测试性,没有合理抽象和分离关注点,导致后期添加单元测试的成本较高 在已经手工测试过证明没有问题的代码上添加单元测试,也让人有画蛇添足的感觉 并且按照以前的习惯,在需求变更或修复Bug后会进行手动测试,现在还要修改单元测试代码,更会造成一种「单元测试维护成本很高」的误解 如果能保证新增的代码都有测试覆盖,整体测试覆盖率就会持续上升 利用TDD(测试驱动开发)的方式,在开发新功能,修复Bug,做需求变更前,先新增或修改单元测试,再修改实现代码,单元测试通过即代表工作完成,减少了大量的手工测试和 Debug时间,在完善的单元测试覆盖下还可以进行大胆重构,这样将极大提高开发效率和代码质量 @小波老嬉

Sent with GitHawk

JimmyLv avatar Jul 22 '18 13:07 JimmyLv

这其实是 TDD 落地过程一个很重要的问题,因为几乎100%的情况(我遇到的项目)能让你有从头起步的机会。于是我们很容易陷入这个先有鸡还是先有蛋的困境:如果先 TDD,发现代码职责杂糅,无法 T,需要先重构代码;如果先重构代码,发现原代码没测试,需要添加测试,而代码职责杂糅,很难添加测试…

于是为了在遗留代码上 TDD/写测试,我们需要有微调手法,甚至有时需要违背重构的原则:没有测试保护不重构代码。这是一般我们传授 TDD 的时候很少涉及回答的问题:

  1. 将新增代码单元化,以便做 UT
  2. 局部代码做微调
  3. 其他手法还在摸索

局部代码做微调,举个例子:

export const isJimmylvAwesome = () => {
  const date = new Date()
  return date.is.not('20xx-02-30')
}

原函数因为不符合 DI 而使得无法 TDD/成本提高,为了测试我们可以在没测试保护的前提下将实现代码微调成:

export const isJimmylvAwesome = () => {
  const date = new Date()
  return isJimmylvAwesomeDependingOnDate(date)
}

const isJimmylvAwesomeDependingOnDate = (date) => date.is.not('20xx-02-30')

实际例子可能比这个更复杂,因而这样的手法也会更有价值。

EthanLin-TWer avatar Jul 22 '18 13:07 EthanLin-TWer

哈哈哈哈,我才发现你的这个时间'20xx-02-30',这是说 Jimmylv 一定 Awesome 呀!

马上给你重构掉:isJimmylvAwesome = () => true

JimmyLv avatar Aug 20 '18 13:08 JimmyLv