• 2011-05-23

    告别mock

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/129902781.html

    在数据上造假。

    如果你只有很短的时间,你已经知道了这篇blog的核心内容了。如果还有时间,请继续阅读。

    别离初因
    mock,是一个经历了大喜大悲的东西。初识mock,以为它就是全部,义无反顾的全身心投入,写出自以为强健无比的软件。但长时间的相处让我们知道,mock只能给予短暂的愉悦。实际经验证明,大量的使用mock,出现变化时,在一片绿色中,整个功能不好用的事屡见不鲜。

    几种选择
    不用mock,并不意味着放弃测试。测试还是要做的,只是我们不希望到处像原来一样到处造“假”。有几种选择方案。

    一切都用真的,这意味着所有一切都跑在真实的环境下。这种做法会导致测试越来越慢。因为在真实的项目里,通常要访问数据库,访问外部系统。我们知道,IO操作会很慢,这种最底层的操作慢下来,会导致整个测试集合都慢下来。

    比如,在一个实际的项目中,我们通过VPN连接外部系统,换句话说,如果这样做,每次运行单元测试之前,我都要连接VPN,很麻烦的。人性告诉我,复杂的事人们会倾向于少做,那TDD本身的快速反馈,就会在这里丧失殆尽。

    还有一种方案,多数内容用真的,少部分内容造假。这就牵扯另一个问题,到底给哪些部分造假。

    数据之源
    绝大多数系统本质上都是对数据进行操作。通常我们编写的逻辑,无非是拿到这些数据之后,进行各种处理。所以,只要我们在数据造“假”,其它部分就可以有效的测试。

    在通常的分层架构中,我们都会有一个专门的数据访问层,没错,它就是我们造“假”的目标。

    假假真真
    虽说要造假,但我们还是希望假得真实一些。

    实际上,在正常的开发过程中,我们都会有一些专门用来测试的数据,比如存放在数据库里。既然这些数据可以放到数据库里,也就可以放到我们造出来的数据访问层里。换句话说,我们造假出的这个数据访问层,可以产生与真实数据库同样的结果。

    要做到这一点,可以把灌到数据库里的数据,也灌到数据访问层里。在实际的项目中,对于数据库部分,我们会维护一个数据库迁移脚本,所有的数据就维护在这个脚本里。本质上说,这些数据是一种元数据,根据元数据可以产生数据库迁移脚本,当然,也就可以根据这些元数据产生假的数据层了。

    在一个项目中,我们把所有的元数据维护在一个简单的csv文件里,然后编写了一个脚本用以产生数据库迁移脚本,还编写一个脚本产生加的数据层。当csv文件被修改时,我们会分别用这两个脚本生成两个文件,一个放到数据库迁移的目录下,一个放到测试部分。

    框架之功
    这里要告别的是mock,而非mock框架。

    前面举的例子都是数据库访问的例子,在某些情况下,我们还可以把外部系统视为一个数据源,那对外部系统的访问也可以归结为数据访问的操作。

    而有些情况下,这些外部访问接口是以API的方式提供的,而且API可能是由很多方法组成的接口,我们真正要用到的方法可能只有几个时,直接实现这个接口会产生出许多无用的空方法。这就是Mock框架粉墨登场的时机了。

    mock框架经过许多年的发展已经相当完善,无论从功能还是表现形式上。而且绝大多数mock框架都可以很好的支持stub。事实上,stub部分才是一个mock框架的核心。

    把mock框架当做stub框架用。这意味着,绝对不要用verify。结合前面的东西,只在不能控制的点使用mock框架。

    分享到:

    历史上的今天:

    画地为牢 2010-05-23
    引用地址:

    评论

  • mock不mock我觉得跟开发时的顺序有关。如果采用自顶向下的顺序,似乎不得不对底层未实现的接口进行mock。以我目前对oo的认识,自顶向下的由上层需求驱动出下层的代码又是很自然很不容易引起过度设计的。

    这篇文章中,我比较不理解的是“大量的使用mock,出现变化时,在一片绿色中,整个功能不好用的事屡见不鲜。”,能否稍微举个例子?
  • Ha,你太有先见之明了。
    这篇blog写于05-23,
    05-24就碰上了由于测试与数据之间的强耦合而带来的大量重构。