Mock不是测试的银弹

发表于:2009-5-19 10:34

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:胡凯    来源:InfoQ

  开发者编写高质量测试的征途上可谓布满荆棘,数据库、中间件、不同的文件系统等复杂外部系统的存在,令开发者在编写、运行测试时觉得苦恼异常。由于外部系统常常运行在不同机器上或者本地单独的进程中,开发者很难在测试中操作和控制它们。外部系统以及网络连接的不稳定性(外部系统停止响应或者网络连接超时),将有可能导致测试运行过程随机失败。另外,外部系统缓慢的响应速度(HTTP访问、启动服务、创建删除文件等),还可能会造成测试运行时间过长、成本过高。种种问题使开发者不断寻找一种更廉价的方式来进行测试,mock便是开发人员解决上述问题时祭出的法宝。mock对象运行在本地完全可控环境内,利用mock对象模拟被依赖的资源,使开发者可以轻易的创建一个稳定的测试环境。mock对象本地创建,本地运行的特性更是加快测试的不二法门。

  我所在团队设计开发的产品是持续集成服务器,产品特性决定了它需要在各个平台(Windows, Mac, Linux等)与各种版本管理工具(svn, mercurial,git等)、构建工具(ant, nant, rake等)进行集成,对于外部系统的严重依赖让我们在编写测试时遇到了很多困难,我们自然而然的选用了JMock作为测试框架,利用它来隔离外部系统对于测试的影响,的的确确在使用JMock框架后测试编写起来更容易,运行速度更快,也更稳定,然而出乎意料的是产品质量并没有如我们所预期的随着不断添加的测试而变得愈加健壮,虽然产品代码的单元测试覆盖率超过了80%,然而在发布前进行全面测试时,常常发现严重的功能缺陷而不得不一轮轮的修复缺陷、回归测试。为什么编写了大量的测试还会频繁出现这些问题呢? 在讨论之前先来看一个真实的例子:

  我们的产品需要与Perforce(一种版本管理工具)进行集成,检测某段时间内Perforce服务器上是否存在更新,如果有,将更新解析为 Modification对象。将这个需求反应在代码中,便是首先通过Perforce对象检测服务器更新,然后将标准输出(stdout)进行解析:

  public class PerforceMaterial {
    private Perforce perforce;
    .....
    .....
    public List findModifications(Date start, Date end) {
        String changes = perforce.changes(start, end);    //检测更新,返回命令行标准输出(stdout)       
        List modifications = parseChanges(changes);//将标准输出解析为Modification
        return modifications;
    }

    private List parseChanges(String output) {
         //通过正则表达式将stdout解析为Modification对象
    }
}

public class Perforce {
    public String changes(Date start, Date end) {
          //通过命令行检测更新,将命令行标准输出(stdout)返回
    }
}   

  相应的mock测试也非常容易理解:

      .....
    ..... 
    @Test
    public void shouldCreateModifiationWhenChangesAreFound() {
        final String stdout = "Chang 4 on 2008/09/01 byp4user@Dev01'Added build.xml'"; //设置标准输出样本
        final Date start = new Date();
        final Date end = new Date();

        context.checking(new Expectations() {{
            one(perforce).changes(start, end);
            will(returnValue(stdout));
        }});//设置perforce对象的行为,令其返回设定好的stdout

        List list = perforceMaterial.findModifications(start, end);//调用被测方法

        assertThat(list.get(0).revision(), is("4"));
        assertThat(list.get(0).user(), is("p4user@Dev01"));
        assertThat(list.get(0).modifiedTime(), is("2008/09/01"));
    } 

31/3123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号