BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

“Classic”与“Mockist”TDD,真的对立么?

| 作者 Mike Bria 关注 0 他的粉丝 ,译者 金明 关注 0 他的粉丝 发布于 2009年2月11日. 估计阅读时间: 7 分钟 | CNUTCon 了解国内外一线大厂50+智能运维最新实践案例。

这周Yahoo测试驱动开发TDD)”小组里面有个热门贴子,是讨论“classic”和“mockistTDD方式之间的对立统一关系。Steve FreemanNat PryceMichael FeathersDale Emery等很多人对这些术语进行了讨论,并描述了各自的工作方式。他们也探讨了是否确实存在这种关系。如果存在这种关系,又是什么从本质上区分开这两种方式?

在声明自己“倾向于classic TDD开发方法”之后,Olaf Bjarnason小组里面用问题——“如果你以前采用classic(方式),是什么让你转向[‘mockist]?觉得新方法怎么样?”——发起了一场超过70条贴子的讨论。然而,前期的回复大多是围绕着Olaf的贴子标题“classic/mockist 讨论”进行的,即是否确有必要进行如此绝对对立的划分。

JMock 的合作创始人Nat Pryce表达了他的看法

我认为把TDD分成“mockist”和“基于状态”是没有意义的,不仅分散了关注点,而且妨碍人们去尝试学习和实践TDD

Mock对象只是一种工具,只是实践TDD时会使用到的工具之一。跟其他工具一样,它们被设计出来以帮助解决特定上下文的一系列问题。脱离了上下文,它们不会有任何帮助,甚至成为障碍。

如果确实如此,那怎么知道何时使用这种“工具”呢?怎么判断测试“状态”(不使用mock),还是该验证行为(使用mock

Dale Emery也加入讨论,讲了他一般是怎么区分的:

很多人使用“基于状态”和“基于行为”的说法来区分。我换了种说法,我认为是“结果”和“协议”。如果是测试UUTunit under test,被测试单元)是否返回了正确的结果,我通常不使用mock。如果是测试UUT是否基于协议扮演了恰当的角色——比如,给定正确的起始条件和影响因素,(UUT)是否向正确的协作者发送了正确消息——我会用mock来代替UUT的直接协作者。

Lior Friedman认为mock的用途是展示一种契约:

对我来说,mock指出了被测试覆盖的类和被(该类)调用的其他类之间存在的“契约”。(mock)测试的目的是确保契约被满足了。

Charlie Poole 就“什么时候使用基于状态(的测试)”提出了他的论断:

如果没有其他办法来观察对象的行为,也就是说如果方法调用只会引起对象外界可观察状态的改变,我会选择基于状态的测试。而假如事实上对象做了些什么,我会[使用mock]验证它的确是做了。

 Adam Sroka 解释了他何时使用mock

就我个人而言,我通常是在系统定义的边界处(比如文件系统、网络、数据库等)使用mock。在自顶而下的开发中,为了得到接口和客户端的松耦合,我通常会使用mock。相反,当交互的对象很小、易于用假对象/stub对象替代时,我一般不使用mock

随着讨论的继续,讨论中反复出现这样的现象(可能上文的摘录也体现了这点):虽然不少贴子的观点类似,但是它们并没有使用通用的分类和命名,只是强调“我们有时这么做,其他时候不是”。而且,每个贴子(可能除了Sroka“自顶而下”的论断)关注更多的是:到底是设计驱动mock,抑或相反,mock驱动设计?

关于mock驱动设计,Michael Feathers给出了如下例子:

对我来说,问题的根本在于人们愿意在多大程度上遵循“tell, don’t ask.mocks支持了这种设计方式。

...

假设你拥有某一类对象,想得到它的错误:

    class Errors {
        int errorCount();
        Error getError(int index);
    }

    Errors errors = object.getErrors();


这就是ask。我们可以基于状态Errors对象进行测试。

为了改成tell,你需要进行如下处理:

    interface ErrorReceiver {
        void accept(Error error);
    }

    ErrorReceiver receiver = ...;
    object.reportErrors(receiver);

我们可以对mockreceiver对象指定预期行为,使之通过测试,而在生产代码中使用“真实”的类。

Steve FreemanJMock的另一位合作开发者)发表了一篇贴子,描述了他的搭档Nat Pryce对一些“值得mock的相关对象组(mock-worthy peer objects)”提出的分类(“Dependencies”,“Notifications”和“Policies”)。在回应的贴子中,Feathers(以及Colin Jack)认为他们两人(FreemanPryce)提出的设计理念实际上就是“mock驱动设计”哲学的核心的一部分。在接下来的讨论中,扼要的讲,当人们提到“mockist TDD”,主要是指这些理念。而且,随着这些更具体的名字,之前反复出现关于“classicMockist TDD”的混淆也减少了。

Pryce提醒小组成员,他和Freeman计划写一本书,提供一些这方面需要的解释。同时他也建议小组成员去参阅他的一篇文章“基于状态与交互的测试”。

坦率的说,这种讨论并不是什么新货色(Google一下),过一段时间就会出现一次。是否存在着“classic TDD”,而它是否又意味着“设计引出mock”或者其他特性?是否存在“mockist TDD”,体现着“mock引出设计”的哲学?“Tell, Don't Ask”,这是否又是完全不相干的东西?不管怎样,这是一种“非此即彼”的分类么,又或者“这种适合这些,那种适合那些”的分类更合适?

当然,一如既往,本文只是摘录了Yahoo小组讨论中的突出部分[希望本文是客观的],仅仅是完整讨论的一部分。你可以自行阅读该贴以及其他相关资料,在这里或讨论贴里与其他人分享你的经验。

查看英文原文"Classic" versus "Mockist" TDD, Distinction Real?

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT