• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

如何设计自动化测试平台和自动化测试框架

发布: 2011-3-11 09:56 | 作者: 网络转载 | 来源: 领测软件测试网采编 | 查看: 227次 | 进入软件测试论坛讨论

领测软件测试网

  最近利用些业余时间自己编写了一个小型自动化测试框架,在设计过程中自己也渐渐对自动化框架的作用有了些新的认识,希望能和大家分享一下。

  其实设计这个框架最初的动机是来源于工作中的一个任务——同事让我维护一个很久以前编写的“自动化脚本”,难度不大,只是一串处理和过程,看懂代码以后只需要修改个别逻辑和参数即可。但后来我想了想,这样纯粹只有过程的脚本,在开发测试时用来当做小工具用不错,但一旦需要建立稳定的自动化测试机制,有大量功能点和测试数据的时候就会显得力不从心。一个功能点对应一个脚本,新增功能点甚至测试数据都需要对应增加脚本,开发维护的成本则会非常高。

  后来我自己尝试去做了一个小型的自动化测试框架,虽然花费了不少时间才实现了原来脚本的内容,但是磨刀不误砍柴工,有了框架,接下来新增功能点的开发工作量大大减轻。自己在设计该框架时也基本上是摸着石头过河,一边思考自动化框架究竟需要做什么,一边也参考一些开源自动化框架例如Ruby Watir的设计方式,以下便是我总结的一些经验和心得。

  一、测试脚本与测试框架脱离

  我开头提到的那个“测试脚本”,从程序启动,测试动作执行,测试结果反馈都一手包干,例如对于A1和A2两个相似的功能点,其测试代码如下:

  功能A-1的脚本:A1Test.java

  public static void main(String[] args) throws Exception {

  // A1测试逻辑实现

  ……

  Class.forName("oracle.jdbc.driver.OracleDriver");

  String url = "jdbc:oracle:thin:@localhost:1521:cui";

  Connection conn = DriverManager.getConnection(url, "cui", "cui");

  ……

  }

  功能A-2的脚本:A2Test.java

  public static void main(String[] args) throws Exception {

  // A2测试逻辑实现

  ……

  Connection conn = null;

  try {

  Class.forName("oracle.jdbc.driver.OracleDriver");

  String connectionUrl = "jdbc:oracle:thin:@localhost:1521:cui";

  conn = DriverManager.getConnection(connectionUrl, "cui", "cui");

  ……

  }

  这样一来A1和A2的测试脚本都可以独立运行,也不需要什么自动化框架,但是原本相似的A1和A2功能,却因为这样的架构要写两次代码,如果TestA1和TestA2由两个不同的程序员编写,那么即便是如上面所示连接一个相同的数据库,每个人需要自己写出实现方式,且都可能有不同的代码风格,这样极大增加了测试代码的编写和维护成本。

  对于测试脚本而言,仅仅只需要负责测试逻辑本身,不应该负责诸如脚本启动,管理的功能,同时降低提升测试脚本编写和维护成本,一些公用的方法例如数据库连接等,都最好封装成方法放在测试框架中,然后供测试脚本调用。

  我在编写自动化脚本时,将每个测试功能点脚本作为一个Scenario类供测试框架调用的,测试框架可以根据用户输入或者任务设定选择执行哪些脚本。

  TestFramework.excute(Scenario userInputScenarioName);

  同时,对于如数据库连接查询这样的操作,也都做了封装,在每个Scenario脚本里,编写者可以通过1行代码就能查询想要的数据:

  在配置文件中填入数据库信息:

  #别名 db_dev #类型 Oracle #IP 127.0.0.1 #端口 1521 #数据库名 db1 #用户名 cui #密码 cui

  在脚本文件中就可以这样来访问数据库:

  String id = DB("db_dev").getSingleResult("select id from ……");

  数据库的链接,关闭工作都由框架进行统一封装。

  二、测试数据与测试脚本脱离

  测试脚本与测试框架脱离后,测试脚本更加专注于业务逻辑,但仅仅这样是不是就够了呢?对于同一个功能点,我们往往也需要测很多数据,如果每个测试数据都“硬编码”到测试脚本里,那么数据增加的时候又要将硬编码的部分代码复制粘贴,犯了和先前一样的毛病:

  // 测试脚本脱离测试框架后的A1Test

  class A1Test() {

  ……

  // 测试A的实现过程

  id = DB("db_dev").getSingleResult("select id from …… where coutry = 'CN'");

  Assert(id == 100000);

  id = DB("db_dev").getSingleResult("select id from …… where coutry = 'US'");

  Assert(id == 200000);

  id = DB("db_dev").getSingleResult("select id from …… where coutry = 'CA'");

  Assert(id == 300000);

  ……

  }

  我们可以看到,虽然测试脚本TestA1的确不再负责程序启动这样的杂事,同时数据链接也更加方便和规范,但是对于多个用例(country值不同,需要校验的id大小不同),仍然需要复制粘贴代码来实现。

  因此我们也需要将测试数据从测试脚本中独立出来,实现“一个框架对应多个测试脚本,一个测试脚本对应多个测试数据”。

  对于这样的测试数据,往往是相对整齐规范的,我们可以用Excel,txt等文件,用表格的方式存储测试数据,然后写出程序逐行读取(jxl可以支持Excel2003以前Excel文件的读取),每一行就是单次测试所需的数据。

  用例ID 用例描述 是否执行 国家缩写 期望结果ID

用例ID 用例描述 是否执行 国家缩写 期望结果ID
1 测试CN对应ID y CN 100000
2 测试US对应ID y US 200000
3 测试CA对应ID y CA 300000

  我采用jxl去读取Excel数据,同时再对参数取用的方法进行简化和封装,最终可以用例如param("期望结果")这样的方式返回当前执行的数据行对应列的数据。

  // 测试数据与测试脚本脱离后的A1Test

  class A1Test() {

  ……

  // 测试A的实现过程

  id = DB("db_dev").getSingleResult("select id from …… where coutry = " + param("国家缩写"));

  Assert(id == param("期望结果ID"));

  ……

  }

  三、总结

  测试脚本从测试框架脱离,即是将“一个测试脚本负责整个测试执行过程”的设计思路变为“测试脚本只负责业务逻辑,一个测试框架驱动多个测试脚本完成测试”。当业务逻辑变化时,我们可以只修改测试脚本和数据而无须修改测试框架,当测试数据需要增加和修改时,我们可以只修改测试数据而无须修改测试脚本,这样的思路归根结底还是来源于面向对象,但不管怎样,提高效率,降低成本才是最终的目的。

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/

TAG: 自动化


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网