他举了这样一个例子,class X有一个叫作badMethod的方法,这个方法处理一些“痛苦”的工作,比如调用并更新产品数据库、或者处理一些甚至关系到底层硬件的事务:
public class X { public void method() { ... badMethod(); ... } ...}
理想的设计是,系统可以允许独立测试一般的类和类组。但如果这个例子没有实现这样的设计,“badMethod是个非final,可覆写的方法”的事实就有利于为获得“测试足够的机动性”提供所需的灵活性,因为它允许“覆写功能并为我们创建一个楔子来让测试变得更简单”:
public class TestableX extends X { void badMethod() { // do nothing } }
Feathers称之为一个seam(接缝),“一个你无须修改便能使用一个功能替代另一个功能的地方”。他相信OO语言提供的缓绑定技术使得其本身比函数式语言的恢复更为友好。
一些评论者,包括Feathers本人在内,都强调了大多数语言都能提供seam的事实:预处理器、继承/多态性和委派、宏和函数指针、高阶函数、动态函数、一等函数、模块边界或monads。。。。。。其中一些人认为,真正关系到可测试性的是底层设计而非编程语言的选择。比如John,他断言,无论使用何种语言,“代码的结构需要首先考虑到简化单元测试。”另一位博客Andrew,强调说如果“代码的结构没有向所需的测试看齐的话”,那么实现将不得不向顺应测试的方向,做相应的修改。因此,他也评论说“关于‘seam’的想法确确实实是瞄准了为实现可测试性而进行恰当设计的底层问题”,也就是说,适当地布置seam。
针对这些争论,Feathers强调说,尽管大部分语言都拥有seam,但关键在于哪种语言用起来更为顺手,尤其是在代码未能以方便测试的方式而设计的情况下:
我同意“针对测试来设计”是真正的重点所在,但我也知道无论我们做什么,总会有一些系统没有以这样的方式来设计。也正是因为这个原因,我非常在乎可恢复性。
[…]
我知道设计seams是可能的,但那不是问题所在。真正的问题在于在它们没有被加入进设计的情况下,而适当布置它们到底有多简单。
[…]
当然,seams也不总是与你所想要实现的测试粒度相一致,毋庸置疑的是,在对seam具有良好支持的语言中,要实现与测试粒度相一致会简单得多,因为seam已经存在那里,也因为它创建新的seam更为简单。
根据Feathers所述,尽管在函数式语言中可以采用其他模型来达到同样的目的,但“这是沉重的”,但Haskell例外。在Haskell中,“大部分你想在软件测试中避免的代码,都可以采用monad来实现”。
尽管Feathers着重指出,他知道人们会辩论说“纯函数式可以满足任何单元测试的需求”,但仍然有许多评论者强力辩论说他没有考虑到函数式语言的细节,以及函数式语言所能提供的机会。Erikd表达了这样一种感觉,他觉得Feathers是在将Java构造器和惯用方法运用到函数式代码中去。
首先,他看上去是在使用Ocaml文法编写Java代码,然后又抱怨说Ocaml不够像Java。他的结论一点都不惊人。Ocaml不是为了编写类似Java这样面向对象的代码而设计的,就是这么简单。
其次,他声称使用函数式语言比Java困难。虽然使用Ocaml文法编写Java代码可能确实很难,但是编写一般的Ocaml代码或函数式代码就不会那么困难了。
很多函数式语言的拥护者强调说,在函数式编程中,是没有副作用的,并且据Greg M.所说,这点可以预防写出需要重构的代码,而且可以将测试变得更为简单:
文章来源于领测软件测试网 https://www.ltesting.net/