议论《不要把Mock当作你的设计利器》

讨论《不要把Mock当作你的设计利器》
ThoughtWorks李晓的这篇文章大家都看了吧,咋没人说点啥呢?http://news.****.net/n/20060726/93003.html

前些日子在这里讨论的很激烈的两个帖子——
什么是“测试驱动开发”和再论要不要全程MockObject,在这篇文章里似乎给出了一些回答,请参与过那两个讨论的相关人员发表下最新的观点!
1 楼 daquan198163 2006-08-02  
感觉文章标题——《不要把Mock当作你的设计利器》很有些吸引观众的意思议论《不要把Mock当作你的设计利器》 ,就像rod的without ejb,不过里面的观点倒没有标题这么极端,比较客观的列举了mock单元测试的优缺点和适用场合,顺便推销自己的mock框架。

我比较同意他指出的mock弊端之一:
引用
Mock Object的行为依赖风险。Mock Object的行为和真实对象的行为必须一致,这在你对真实对象进行重构的时候是很大的风险。即使当前Mock Object的行为和真实Object的行为完全一直,而且所有测试都覆盖到了,其结果也很可能是:代码一处修改,测试到处失败。实际开发过程中这种情况是非常常见的,而且已经有不少人依赖这一点来修改代码了。其方法是先修改代码让所有依赖这块代码的测试都失败,然后再一点一点修改测试代码让测试通过,这看起来还非常不错。

其实也就是测试代码与实现代码存在大量重复。
2 楼 yuxie 2006-08-02  
说得有一定道理。偶也很痛恨写长长的setup。重构起来也比较烦。不过偶不会为了mock而写接口。easymock的classextension还是很好使的。现在我越来越体会不到接口的作用了。偶痛恨在ide里跳转的时候不能直接跳转到具体的实现上。

不过作者啰里啰唆一堆,最后也没有提出好的解决办法。作者说得“依赖一个设计简单、职责清晰的代码环境,”并不是解决办法。mock本来就是模拟不是这个类职责的工作。生亦何欢,死亦何苦,该mock还是得mock的~
3 楼 gigix 2006-08-02  
ThoughtWorks中国公司总经理郭晓的回复:
Xiao 写道
I did have some doubts about using Mocks when i was programming, similar reasons - too hard to refactory, too brittle. And i total agree with the three places to use it - external resources (I/O), UI, third party API.
4 楼 抛出异常的爱 2006-08-09  
yuxie 写道
说得有一定道理。偶也很痛恨写长长的setup。重构起来也比较烦。不过偶不会为了mock而写接口。easymock的classextension还是很好使的。现在我越来越体会不到接口的作用了。偶痛恨在ide里跳转的时候不能直接跳转到具体的实现上。

不过作者啰里啰唆一堆,最后也没有提出好的解决办法。作者说得“依赖一个设计简单、职责清晰的代码环境,”并不是解决办法。mock本来就是模拟不是这个类职责的工作。生亦何欢,死亦何苦,该mock还是得mock的~


MS:F5可以跳到实现中吧
5 楼 daquan198163 2006-08-09  
抛出异常的爱 写道
yuxie 写道
说得有一定道理。偶也很痛恨写长长的setup。重构起来也比较烦。不过偶不会为了mock而写接口。easymock的classextension还是很好使的。现在我越来越体会不到接口的作用了。偶痛恨在ide里跳转的时候不能直接跳转到具体的实现上。

不过作者啰里啰唆一堆,最后也没有提出好的解决办法。作者说得“依赖一个设计简单、职责清晰的代码环境,”并不是解决办法。mock本来就是模拟不是这个类职责的工作。生亦何欢,死亦何苦,该mock还是得mock的~


MS:F5可以跳到实现中吧

什么IDE有这个功能呀?
6 楼 YuLimin 2006-08-09  
daquan198163 写道
抛出异常的爱 写道
yuxie 写道
说得有一定道理。偶也很痛恨写长长的setup。重构起来也比较烦。不过偶不会为了mock而写接口。easymock的classextension还是很好使的。现在我越来越体会不到接口的作用了。偶痛恨在ide里跳转的时候不能直接跳转到具体的实现上。

不过作者啰里啰唆一堆,最后也没有提出好的解决办法。作者说得“依赖一个设计简单、职责清晰的代码环境,”并不是解决办法。mock本来就是模拟不是这个类职责的工作。生亦何欢,死亦何苦,该mock还是得mock的~


MS:F5可以跳到实现中吧

什么IDE有这个功能呀?


Eclipse啊,用插件:Implementors,右键直接让你选或者跳到具体的实现中去,很方便的。

使用详见:http://iamin.blogdriver.com/iamin/1098046.html
7 楼 charon 2006-08-11  
这个再早以前好像也讨论过了,把testcase写得白盒\黑盒还是灰盒一点.越白稳定性越差.

我现在是能不白盒就不白盒,这玩意儿重构起来是个累赘.但是,从TDD中testcase的本意来说,至少是灰盒的,这个testcase并不是在检验接口或者公共方法的I/O语义,而是在某种程度上固定这个方法的实现(这个很有道理,但是很不方便,不好维护). 不过mock并不一定需要接口,easymock很早就可以搞定这个了,为了mock而搞出一堆接口来,那也太不符合KISS了.

这个哥们对mock的应用场合还是写得比较好的.不过,现在我现在除了测试之外,发现交互式编程在某些场合,比如对文件的读取,网上资源的抓取等等中,是一个非常好的手段(这个时候肉眼判断比编写mock高效多了,而且还有点集成的味道,这个是mock做不到的).先在交互环境下执行之,然后复制到文件里面.当然只能用于ruby和python之类的动态语言程序的开发
8 楼 凤舞凰扬 2006-08-14  
我倒觉得这本身就是不是问题的问题. Mock本身就是假设某种行为是正确的,从而保证单元的独立性,又何来行为依赖呢? 什么地方都去用Mock自然是带来重构也好,测试跟踪也好的麻烦了.
      我们总是谈单元测试,谈测试驱动, 才发现并不是大家对于单元的概念有比较统一的理解.自然而然,由此引申的相关Mock也就变得问题多多了.
9 楼 woodhead 2006-08-16  
Mock有自己的价值,但滥用Mock除了文里列出的种种弊端外还会使TDD失去一些很重要的意义。TDD能够优化设计的原因之一是你必须要仔细思考设计以使你的代码能够被自动测试,从而降低设计的耦合性。Mock的出现使得这种必要性明显降低。
我认为Mock的价值主要在于模拟网络连接,消息队列,对象序列化服务之类依赖于环境的地方。
10 楼 raimundox 2006-08-19  
woodhead 写道
Mock有自己的价值,但滥用Mock除了文里列出的种种弊端外还会使TDD失去一些很重要的意义。TDD能够优化设计的原因之一是你必须要仔细思考设计以使你的代码能够被自动测试,从而降低设计的耦合性。Mock的出现使得这种必要性明显降低。
我认为Mock的价值主要在于模拟网络连接,消息队列,对象序列化服务之类依赖于环境的地方。


马教主有一篇文章叫mock不是stub....
11 楼 凤舞凰扬 2006-08-21  
yangxp_82 写道
gigix 写道
ThoughtWorks中国公司总经理郭晓的回复:
Xiao 写道
I did have some doubts about using Mocks when i was programming, similar reasons - too hard to refactory, too brittle. And i total agree with the three places to use it - external resources (I/O), UI, third party API.

一语中的。

    我倒不觉得他所说的完全正确, Mock还有一个更有用处的地方, 在一个多模块的商业项目中,  简单讲, 甲负责完成A, 乙负责完成B, 而A需要通过接口调用B实现, 这个时候, 因为项目的时间安排的关系, 甲完成了自己的代码, 而乙并没有完成B实现, 在这个时候,难道甲的单元测试不做了么? 使用Mock的目的就在这里了. 作为单元测试本身的概念, A是独立的单元, 它的单元测试只需要测试A本身的(如果连同B也考虑进去, 那只能是集成测试了).所以在这个时候需要做的就是假定B已经完成,并且正确, 基于此对A进行单元测试.
     Mock用烂绝对不是Mock的错, 而是使用Mock的人根本就没有理解Mock的真正目的和使用范围.
12 楼 grave 2006-08-27  
凤舞凰扬 写道

    我倒不觉得他所说的完全正确, Mock还有一个更有用处的地方, 在一个多模块的商业项目中,  简单讲, 甲负责完成A, 乙负责完成B, 而A需要通过接口调用B实现, 这个时候, 因为项目的时间安排的关系, 甲完成了自己的代码, 而乙并没有完成B实现, 在这个时候,难道甲的单元测试不做了么? 使用Mock的目的就在这里了. 作为单元测试本身的概念, A是独立的单元, 它的单元测试只需要测试A本身的(如果连同B也考虑进去, 那只能是集成测试了).所以在这个时候需要做的就是假定B已经完成,并且正确, 基于此对A进行单元测试.
     Mock用烂绝对不是Mock的错, 而是使用Mock的人根本就没有理解Mock的真正目的和使用范围.


我觉得mock大部分应该是这种应用场景..至少在我所在的公司是这样.
13 楼 hyysguyang 2006-09-13  
同意凤舞凰扬,是人的问题,不是工具的问题。不止mock,其他的也是一样,就像不同的人写jsp一样,写出来的也不一样。
14 楼 tianxinet 2006-09-13  
基本上反对全程使用mock,有些反对大量使用mock。
如果不是纯粹的“测试先行”者,单元测试更多是“集成单元测试”、“功能单元测试”,不使用mock更有理由。

不过mock还真是有些好处,比如模拟exception还真是不错,有些异常很难得呀。
15 楼 shaucle 2006-12-04  

俺以前用过easyMock和jemmy等去实现一个项目.

后来分析一下,发现80%是不必要的(或是带来额外的trouble)

结论:mock是有用,但不是到处可用.
16 楼 lane_cn 2006-12-04  
mock的问题在于,你实际上不是在检查一个对象的接口,而是深入到了实现过程中。

stub和mock的使用是有很大区别的,stub的用法是:假设一个对象是正确的,在这个基础上检查其他对象的接口。比如:我们假设A类肯定是对的,在此基础上检查B对不对,于是就制造一个A-stub。而mock是用来检查A的实现过程到底是不是对的。

mock实际上是和面向对象的设计原则相违背的,他是在深入一个过程,去检查实现细节。因此mock用的多不多,体现了这个程序设计的内聚性好不好。如果程序中到处都需要用mock来测试,说明程序的内聚性不高。

比如说有这样的需要:A向数据库里面写一个数据,然后B从数据库里面读这个数据。这样的设计从道理上来说就是不合理 的,既然是同一段逻辑,就应该封装在同一段代码中,外界只应该关注他的接口,而不应该知道这个数据的定义。对这段代码进行测试,也只需要测试他的接口。如果需要知道实现过程对不对,数据在表里面到底保存了没有,这时候就可以使用mock。即使是这段代码里面错翻天了,也不应该对其他代码造成损害,至少接口是对的。这就把mock的使用范围和影响力减到最小了。
17 楼 shaucle 2006-12-05  
楼上所言极是
18 楼 liuyifan.com 2006-12-09  
Xiao 写道
I did have some doubts about using Mocks when i was programming, similar reasons - too hard to refactory, too brittle. And i total agree with the three places to use it - external resources (I/O), UI, third party API.


外企牛人e文就是好