mock.VerifyAll()? NO!

TDD我用的很久了,Mock这东西倒没怎么用过。主要是这两年都在写那个nlp的framework,一手一脚搭起来的东西,完全是由底而上,基本需要被交互的interface都有了instance class。也就自然在Junit中写

XXXinterface xxx=new XXXinstance

从而没有必要去面向interface编程了。

最近到了新单位,开始用CAB,遇到了MVC的问题。那种giant view自然不是testable的,在网上搜到了http://codebetter.com/blogs/jeremy.miller/archive/2007/06/04/build-your-own-cab-part-6-view-to-presenter-communication.aspx 的帖子,觉得其中所说的dump view挺符合我的审美观,试着用了用,在測presenter的时候自然就遇到了mock view的问题。

过于mock对象以前了解过一些,原以为倒也不难。找了下.net下常用的几种mock framework,看了些比较,rinho mock2好评比较多,就去code project下了个demo来看看。这一看倒是看出问题来了。

            MockRepository mocks  =   new  MockRepository();
            IProjectView projectView 
=  (IProjectView)mocks.CreateMock < IProjectView > ();
            Project.Project prj 
=   new  Project.Project( " Example Project " );
            IProjectPresenter presenter 
=   new  ProjectPresenter(prj, projectView);
            Expect.Call(projectView.Title).Return(prj.Name);
            Expect.Call(projectView.Ask(question, answer)).Return(
null );
            mocks.ReplayAll();
            Assert.IsFalse(presenter.SaveProjectAs());
            mocks.VerifyAll();

前面几句,创建一个mock生成器,用Expect设置对象的返回值。这里我对Expect还不太理解,直觉这个命名不太容易理解,不过也可以接受。然后Assert一个结果。到此为之都没问题,可是最后一句mock.VerifyAll()是干吗的呢?

去查了下文档,VerifyAll是说如果我不按照预订的顺序调用mock对象中的方法,MockRepository会抛出异常——这一下我就炸锅了——感情我用Mock的话不但要关心mock对象的返回值,还要关心它的内部实现啊。

第一个反应这就是违反了OO中封装的原则。按照封装来说,一个Object暴露出来一个function就是承诺其能实现一定的功能,至于其内部实现,对不起,就不是调用者该关心的了。人家爱到月球转一圈也可以,只要能完成contract中规定的事就行了。您自己写个单元测试也就只需要测所有交互对象能按照contract保质保量提供服务的情况下被测试的function能否干好自己的活儿就行了,管那么宽干吗?

先以为是我理解上的问题,就去google了一把。这一看,原来虚拟对象还分好多种,我以前一直用的那种其实都是个stub,如果真正用mock的话就得是管的这么事无巨细。网上对mock的争论也挺多的,也有很多人说大多数情况其实用stub就够了,只有在牵涉到file,db,network时要用用mock。

话虽然这么说,我也没想明白为什么要在牵涉到这三种资源时用mock啊。在我看来,mock和stub(不论其实现)最大的区别就是mock要管人家实现,人家没按你所理解的实现你还不认,而stub不用像太平洋警察管那么宽。那我觉得是无论如何没法接受mock的。在我的理解中,对于一个function来说,它和外界的contract只应该包括input arguments, post-condition和return result。至于内部实现,是万万不应该暴露的。比如对于一个inc()来说,内部究竟是写成

i ++ ;

 

还是

i = i + 2 ;
emptyfunction1();
int  j = i - 1 ;
emptyfunction2();
i
= j;

 

都不是调用inc()的方法该关心的。如果其明确声明inc()不会调用emptyfunction1()和emptyfunction()2并在contract中要求调用者检查的话是一种推卸责任的行为。这样一来,一旦inc()改变了内部实现,所有调用inc()的对象都要去修改test case,这是何等紧密的耦合啊!

所以,至少到现在,我找不到用mock的理由。以后我要测试的话还是宁愿写个stub,最多是用用PartialMock之类不会要求校验内部实现的方法。至于那行mock.VerifyAll(),在我找到充分理由之前是绝不会用它的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值