姚若舟在微博上提到实际工作中的一件事:上周和同事讨论时,我发现他的代码有不少行为都没有被单元测试覆盖。他的解释是那些代码属于一些极端情况的出错处理,用单元测试去覆盖不值得(需要额外的隔离)。我问他为什么不删除这些代码,他的回答是删了代码评审过不了。我不认同,不过考虑他刚开始写单元测试,忍了。大家怎么看?

  大家针对这个问题给出了各自的意见:

  吴穹adam:不一定所有行为都必须在单测覆盖的 这个要看分层测试的规划是什么。

  Robin圈:1. 首先,要清楚,在该极端情况下,应不应该出异常。有时候出异常才是期望结果。之后,我们才能决定评审的标准。2. 是否测试是根据价值来分割的,而非事件发生的频率。比如站点初始化,极少发生,却很有测试必要。极端情况,类比分析。

  Ethan苏于登:想问下总体关键,价值在哪里?如果那段代码无价值,跟若舟想法一样,或许可以删掉。如果代码审核流程不能合适体现价值,应该考虑修改?如果那段代码确实有价值,因为边缘状况确实有可能出现,那加单元测试覆盖其实是很有价值的。

  林曙?:黑盒测试有一种技术基于风险的测试(RBT),其思想也许可以借用到白盒测试。其基本思想是测试不可能控制全部风险,所以必须面对风险作出抉择,合理安排你的测试投入。其基本公式是 风险=问题发生时的破坏性×问题发生的可能性。所以不能只考虑风险的单个因子。

  steedhorse:如果能用20%的付出获得80%的测试覆盖率,我觉得这是好事,而不是坏事。相对于不写单元测试,这也已经是不折不扣的“质的飞跃”了。然后,哪20%是可以牺牲的呢?我觉得错误处理属于可以牺牲的。很多时候错误处理的目标仅仅是fail fast,即让程序当场死掉,而不是带着错误继续运行,然后在其它地方莫名其妙地死掉。fail fast更多只是一种对待错误的策略,并不强求程序有确定的行为。所以我觉得在单元测试中这属于可以牺牲的部分。

  姚若舟针对实际的情况,对以上微博做出回复:

  回复@吴穹adam:我提到的案例,代码行为我觉得比较适合在单元测试中覆盖,而且也比较高效。不知道分层测试的规划主要是指哪些方面?

  回复@Robin圈:我的案例来说,我觉得所谓添加测试价值不高更像是一种托词和惰性吧。其实,那些代码被使用的机会不是很极端,但是加测试需要做一些隔离,甚至是一些代码抽象,所以不愿意了。我很赞同TDD的观点,是没有失败的测试,不应该写出任何多余的代码来。

  回复@Ethan苏于登:我很认同。不过,这些改变或许要慢慢来吧。

  回复@林曙?:我在写单元测试的时候,不会考虑加或不加某个测试的风险和危害有多大的。想到有必要的测试加了,反正单元测试都很简单直接而且运行很快。如果不加,一般都是被测试代码不需要的行为。如果单元测试充分的话,会使集成测试的数量大大减少。那时,根据风险评估来考虑如何添加测试,也许不再重要了。

  回复@steedhorse: 刚开始这样做,我可以理解。不过复杂的遗留代码系统中,大概没有什么错误处理的是可以fail fast。以后,还是应该尽量用测试来覆盖这些代码吧,不过牺牲他们了。

  大家对这个话题进一步讨论:

  吴穹adam:测试金字塔我认同的,单元测试应该多写,但还是要以风险为依据针对正确的单元来写出可维护的单元测试。

  杭州李云:作为专业的软件开发工程师,那些边边角角一定要覆盖到,否则将大大降低单元测试的效果。这容易形成错误的推理:“单元测试因为边角不覆盖,所以测试效果不好;测试效果不好,所以单元测试效果不好;测试效果不好,所以单元测试不要那么认真。”

  @不许说话: 另外,按理说,单元测试是敏捷方法必备实践。而ACRD推行的scrum是敏捷方法的一种,自然必须首先符合敏捷的实践,然后才谈得上scrum。现在,scrum也几年了,敏捷实践呢?如果不能先一般性的敏捷实践,再scrum,我看着邪路回不了头了。