关闭

mock.VerifyAll()? NO!

1017人阅读 评论(0) 收藏 举报

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(),在我找到充分理由之前是绝不会用它的。

0
0

猜你在找
【套餐】Hadoop生态系统零基础入门
【套餐】嵌入式Linux C编程基础
【套餐】2017软考系统集成项目——任铄
【套餐】Android 5.x顶级视频课程——李宁
【套餐】深度学习入门视频课程——唐宇迪
【直播】广义线性模型及其应用——李科
【直播】从0到1 区块链的概念到实践
【直播】计算机视觉原理及实战——屈教授
【直播】机器学习之凸优化——马博士
【直播】机器学习&数据挖掘7周实训--韦玮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6349次
    • 积分:138
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档