我们码农除了写代码以外,还要对代码写单元测试来进行测试。

但是我们往往写好了代码,却发现这代码没办法写测试了。

最大的问题是,往往没有很有效的办法对代码中的对象进行mock,因为那个地方是在函数里面的代码行,它mock不了。

我举个例子,有一个函数,里面会new出来一个类的对象,这个对象会访问外部系统,所以需要mock。然而并没有很好的办法,因为这个new是在函数里面的代码的new。

那么这时候就有人说了,你这个代码如果发现不好写测试的话,那么就说明是你这个代码的结构写的有问题,好的代码都是能很顺畅的写测试的,能不能顺畅的写测试可以反过来验证代码的好坏,你可以不断的改进你的代码让它能越来越顺畅的写测试,那样你的代码的结构也会越来越好的。

bullshit。

在一个很普通的函数里写一行new有罪吗,new何罪之有?写一行new不正常吗?

高内聚,什么是高内聚呢,就是要你的逻辑都成块在一起密度很高,一行new正是高内聚的体现,这是非常正常的代码。(当然事情不能绝对,高内聚不等于完全内聚,完全内聚就是一个class里写了所有逻辑,物极必反)

正确的真相就是高内聚对写测试代码不利,这两者是矛盾的,正是因为高内聚了所以不好mock。

那么这种情况下怎么写测试代码呢,此时就要用《重构》或者《修改代码的艺术》中所说的提升法,写一个可以mock的函数来放置这行new。总之此时唯有提升这种办法才能有用。

那么一提升,一行代码提升成了一个函数,不但一行变三行变多了,逻辑上还又多了一层,本来你这行new和上下行都逻辑紧密的联系着,此时你这行new被一行函数调用替代了,上下间的逻辑联系就不那么紧密了,我要看这个函数里面是什么还得跳到这个函数的地方去看,一跳,那种酣畅淋漓一扫到底的看文章的感觉就没有了,是不是。

为了要写测试,一提升,高内聚就没那么高内聚了,内聚程度下降了,下降的内聚哪里去了呢,跑去耦合了,所以耦合的程度上升了。

也就是说为了要写测试,生产代码的质量下降了。

所以我说,根本就没有生产代码和测试代码一派和谐互相帮助改进代码结构这种事情,两者本质上是矛盾的,互相打架。

那么这时又要做出平衡点的选择了,在生产代码的质量和测试代码的容易写程度间做出平衡点的选择。又要假象一根进度条,左边是最高的生产代码质量和最不容易写测试,右边是最低的生产代码质量和最容易写测试。

该怎么选呢,非常简单,只要你想一下,你写的测试代码会进入生产环境跑起来吗?不会的,所以一旦出了bug,你吭哧吭哧费了老大老大劲debug的代码是什么代码?是生产代码。而测试代码一般是写完了就不会多看一眼的。

所以,选择一定是优先保证生产代码的质量。

当然任何问题都不能太绝对,如果你要把进度条往左拉到底,那么你可能很多测试代码都没法写了,所以只能优先适度保证生产代码的质量。当然还要考虑effort,你保证生产代码质量了,结果写测试代码要n倍于写生产代码的时间,那也不合适。

所以我想说的其实是,影响生产代码质量有很多的因素,除了需求本身的因素以外,其实测试代码也在制衡生产代码的质量,这就是为什么对于简单需求你写出来的代码总比你估计的代码要差一些的原因。

最后,有的人喜欢往右一拉到底,这就是构造函数DI,滥用DI搞的乌烟瘴气,维护困难,苦不堪言。

上一篇 下一篇