敏捷自动化测试(1) —— 咱们的测试为何不够敏捷?

    做者: 殷坤  来源: InfoQ html

 测试是为了保证软件的质量,敏捷测试关键是保证能够持续、及时的对软件质量状况进行全面的反馈。因为在敏捷开发过程当中每一个迭代都会增长功能、修复缺陷或重构代码,因此在完成当前迭代新增特性测试工做的同时,还要经过回归测试来保证历史功能不受影响。为此咱们指望: web

  测试范围足够广: 编程

  • 测试用例要覆盖全部功能;
  • 要在各类可能的环境下做兼容性测试;
  • 系统的稳定性、性能都要测试;

  测试频率足够高: 浏览器

  • 每日构建产生的版本要保证可用;
  • 每一个迭代都须要对历史功能作回归测试;
  • 释放前或上线后若是打了补丁,就须要回归;

  但实际状况每每不遂人愿: 并发

  实际测试周期变短: 框架

  • 上线时间提早肯定,研发进度延期,测试计划被迫延后;
  • 最后阶段常常会临时增长测试任务;
  • 全部人都知道还须要再通过一轮测试,但时间没有了;

  有效测试资源稀缺: 编程语言

  • 临时从其余项目抽调的测试人员不能马上有效的开展测试工做;
  • “搞不清楚”本项目的研发人员究竟是不会作测试仍是不肯作测试;

  所以因为客观上的资源和时间限制,完整的、及时回归测试在人工测试状况下,每每是不可能完成的任务。团队内部也会产生各类争执: 函数

  • 提交给测试的版本为何研发人员不先作经过性测试?
  • 此次代码改动量不大,有必要再花那么多时间回归么?
  • 当初不是承诺此次修改确定不会影响之前的功能么?
  • 怎么不早说要支持Chrome浏览器,如今哪还有时间测试啊?
  • 怎么能让现场出现这种低级的Bug,打补丁后为何不仔细回归一遍?

  争执越演越烈,最终有团队成员爆发了:“这简直不是人干的活!”。 工具

  您怎么看待这句话呢? 布局

  其实话糙理不糙,用更理性的语言翻译一下就是“有些工做不该该以人工的方式来完成”,好比:

  • 大量机械的、重复性的回归测试;
  • 结果的正确性不依赖主观判断的测试;
  • 须要模拟大量数据、大量并发量的测试;
  • 须要不间断执行的测试(好比7*24小时持续执行);
  • 须要短期内完成的大量测试用例执行(好比完整的功能回归测试);

  经过自动化测试能够极大的提高回归测试、稳定性测试以及兼容性测试的工做效率,在保障产品质量和持续构建等方面起到举足轻重的做用。特别是在敏捷开发模式下,自动化测试是必不可少的。

  目前业界的商业/开源自动化测试工具备不少,好比,功能测试工具备QTP、Selenium等,性能测试有LoadRunner、JMeter等。其工做原理无非都是经过“测试脚本”和“测试数据”来完成“测试过程”,并比较“测试结果”,进而造成“测试报告”。

  本文不对这些测试工具的差别或优劣进行对比,只以做者目前采用的Selenium为例进行分析:敏捷开发模式须要自动化测试,但自动化测试自己的敏捷性又如何呢?

  Selenium是针对Web应用的开源自动化测试工具,经过编写模拟用户操做的脚本,它会打开浏览器对Web应用进行黑盒测试。能够方便的用于功能测试、兼容性测试、 稳定性测试及并发测试。目前已被主流浏览器厂商普遍支持,同时也是不少其它自动化测试工具(好比,RobotFramework)的底层核心技术。Selenium由IDE、Remote Control(简称RC)、WebDriver、Grid四个工程组成:

  • Selenium IDE

  是一个用于录制/回放测试脚本的Firefox附加组件,录制的脚本能够生成基于Selenium RC的测试代码(Java、Ruby、C#等)。适用于快速入门,不太适用于实际较大的测试项目;

  • Selenium RC

  RC由Server和Client组成两部分组成,Server负责加载/关闭浏览器以及做为HTTP代理来访问Web应用,Clinet支持多种编程语言和测试框架(TestNG、JUnit、NUnit等)。

  • Selenium WebDriver

  WebDriver做为Selenium2的核心特性提供比RC更简洁易用的API,是官方推荐的RC替代方案。能够更好的支持动态网页,不须要再额外启动一个独立的Server。

  • Selenium Grid

  是Selenium的一个扩展工具,能够很方便地同时在多台机器上和异构环境中并行运行多个RC或WebDriver用例。

  Selenium RC是经过在浏览器加载时“注入”JS函数来操纵后续的浏览器行为,Selenium WebDriver则经过直接调用各个浏览器内置的本地事件来达到这一目的。WebDriver目前已经做为W3C规范草案,提交由Google、Mozilla等浏览器厂商讨论。

WebDriver规范定义一组与平台、语言无关的接口,包括发现和操做页面上的元素以及控制浏览器行为,主要用于支持Web应用的自动化测试。 WebDriver的核心是经过findElement方法返回DOM对象(WebElement),经过WebElement能够对DOM对象进行操做 (获取属性、触发事件等)。其中findElement方法须要的元素定位器(Locator)支持ID、XPath、CSS、超连接文本等多种方式。

  “WebDriver”顾名思义就是“Web浏览器驱动”,它专一于解决如何经过外部命令(一般为测试用例)操做浏览器的问题。至于测试用例按照什么顺序执行、执行过程当中如何传递数据、测试结果如何断言、如何报告,则能够经过集成其它优秀的专业测试框架(好比,TestNG)来实现(WebDriver没有必要重复造轮子)。

  下面用以“用户管理”为例,来看看用WebDriver实现的“增长”和“删除”测试脚本(只示意部分关键代码)。

  一、在用户列表页面点击“新增”按钮,跳转到新增用户页面:

webDriver.findElement(By.xpath("//a[contains(@id,'addUserBtn')]//button")).click();.

  脚本解读:

  • By.xpath()表示经过XPath来定位页面元素;
  • click()表示在找到的当前控件上执行点击操做;

  二、在新增用户页面,输入“账号”、“密码”、“姓名”,选择“性别”、“生日”和“国籍”,而后点击“保存”按钮,回到用户列表页面,并判断是否增长成功:

1)  String account="autotest2";  2)  webDriver.findElement(By.xpath("//div[contains(@id,'account_userForm')]//input")).sendKeys(account); 3)  webDriver.findElement(By.xpath("//div[contains(@id,'password_userForm')]//input")).sendKeys("1");  4)  webDriver.findElement(By.xpath("//div[contains(@id,'name_userForm')]//input")).sendKeys(account);  5)  webDriver.findElement(By.xpath("//div[contains(@id,'sex_userForm')]//input")).click();  6)  webDriver.findElement(By.xpath("//span[text()='女']")).click();  7)  webDriver.findElement(By.xpath("//div[contains(@id,'birthdate_userForm')]//input")).click();  8)  webDriver.findElement(By.xpath("//div[contains(@id,'nationality_userForm')]//input")).click();  9)  webDriver.findElement(By.xpath("//span[text()='中国']")).click();  10) webDriver.findElement(By.xpath("//a[contains(@id,'userSaveBtn')]//button")).click();  11) WebElement ele = webDriver.findElement(By.xpath("//div[text()='"+account+"']")); 12) Assert.assertNotNull(ele);

  脚本解读:

  • sendKeys ()表示在找到的当前控件上输入字符;
  • 2~9行表示经过输入或点击选择的方式为用户相关属性赋值;
  • 第10行表示点击“保存”按钮(点击后会自动转向用户列表页面);
  • 11~12行表示查找页面上文本内容为新增账号的div,并断言该div是存在的(不为空);

  三、删除刚刚增长的人员,而后判断是否删除成功:

1)  webDriver.findElement(By.xpath("//a[contains(@id,'deleteUserBtn')]//button")).click();  2)  WebElement ele = webDriver.findElement(By.xpath("//div[text()='"+account+"']"));  3)  Assert.assertNull(ele);

  脚本解读:

  • 第1行表示点击“删除”按钮;
  • 2~3行表示查找页面上文本内容为新增账号的div,并断言该div已经不存在了(为空);

  经过上面的脚本就能够实现“用户增长、删除”的自动化测试,而且能够跨浏览器。看到这里您会不会以为总体还不错,若是测试脚本再能经过录制的方式自动生成就更好了!

  “看”起来确实还不错,但在实际项目中用起来就没那么爽了。这实际上是在技术/工具选型时广泛存在的现象:在验证/试用阶段的评价很高,但在投入生产使用时会遇到各类各样的问题,所以你们在选型阶段除了考虑功能,还要考虑技术/工具自己的开放性和可扩展性。

  上面的方案单纯从技术的角度来说是很不错的:开源、社区活跃、标准化程度高、支持跨浏览器、脚本回放稳定、可集成性高,等等。

  可是若是就这样应用在实际项目中,会从过程的角度暴露一些棘手的问题:

  • 测试脚本是“代码级”的,那么应该由谁来编写呢?

  测试人员和开发人员好像都有编写这些测试脚本义务,但彷佛又都有不写的理由。

  • 测试脚本必须不断的修改才能在最新版本上跑通,谁该为此买单?

  在敏捷开发过程当中须要快速响应需求的变化(新增、变动),这一点整个团队都好理解。所以若是需求发生变化,开发人员修改代码、测试人员修改测试 脚本,一切瓜熟蒂落,你们相安无事。可是在用户需求没有变化时,开发人员频繁修改代码的状况也很常见:好比,修改Bug、针对“坏味道”作重构、调整页面 布局或样式。因而在“毫无征兆”的状况下,测试脚本又没法执行了!

  这时候测试人员可能会质问开发人员:“作以前怎么不想清楚?都已经测试完成的功能,为何还老是反复修改?何时代码才能稳定?”。

  而开发人员此时也会很是义正词严:“有Bug能不改么?页面布局不合理致使用户体验差,能不改么?并且敏捷中的一个重要的实践就是重构啊”。

  你们又是彷佛都有道理、也都有苦衷。我虽然做为测试人员,可是在这个问题上仍是“偏向于”开发人员的: 在软件生命周期的各个阶段(需求、设计、开发、测试)中,后面的阶段对前置阶段是有必定依赖的,因此越日后期响应变化的难度越大。好比,在“开发”环节不 仅须要响应“需求”的变化(新增、变动),并且须要响应“设计”的变化。从这个角度来看,“测试”本就应该响应“开发”的变化。

  对于在实际项目自动化测试过程当中遇到的上述问题,归根究竟是由于“自动化测试方案自己的敏捷程度不够”,主要体如今以下三个方面:

  一、 学习成本高

  测试人员除了要掌握WebDriver接口以外,还要掌握XPath、TestNG的用法,甚至还须要对功能的前台实现有必定了解。

  二、 脚本维护困难

  敏锐的开发/测试人员从上面的示例脚本中,能够立刻嗅出一些“坏味道(Bad Smell)”: 代码类似度很是高、可能变化的数据被硬编码在测试代码里、代码可读性差、测试代码与页面源码耦合度大,等等。这些坏味道的出现,一般意味着须要进行重构, 不然会愈演愈烈,最终变得尾大不掉。

  【注】业界常见的测试工具本质上仍是针对页面源码来编写(或生成)测试脚本的,即便提供了录制工具,此类脚本的可读性和后期可维护性仍是很是差的。

  三、 断言条件繁琐

  业界常见的测试工具即便提供录制脚本的功能,可是对于“断言”仍是须要人工插入的(工具作不到智能的判断咱们想要在哪里设置断言),因而断言就成了自动化测试人员的“噩梦”。

  断言对象可能很“多”,页面的信息量每每很大,须要在测试脚本中为每一个断言对象(好比,页面某个文本框的值)补充断言语句。

  预期结果是可能“变”化的,甚至是动态的,所以预期结果的值若是与脚本逻辑耦合在一块儿,未来极难维护。 断言机制比较“呆”板,对于 未设为断言对象的字段,若是发生错误也是没法感知的,而且难以对于UI样式或UI逻辑(好比,翻页图标应该灰显)进行断言。

  换个角度能够理解为,若是这样的断言条件“多”的话,整个测试用例集会“变”的很是“呆”板!

  想要有效的改善这些问题,就必须让自动化测试变得“敏捷”起来!

  在本系列后续的文章中会就“如何让测试脚本易写、易读、易维护”、“如何让断言再也不成为测试的负担”、“如何经过持续集成让测试用例发挥更大的价值”进行详细的介绍,敬请关注!

相关文章
相关标签/搜索