完善的校验,是自动化测试的核心之一。完全覆盖功能测试用例的自动化脚本,才能代替手工测试,真正解放手工劳动。

  下面探讨一下自动化测试中的校验,包括:需要做什么样的校验、自动化实施、存在的问题及解决方案。

  1. 需要做什么样的校验

  从我目前的经验来看,web功能测试的校验点可以分为2种:数据持久层校验和UI校验。

  数据持久层可能是DataBase(oracle、mysql),也可能是文件系统(tfs、tair等)。

  UI可能是页面提示,可能是alert弹出框,也可能是页面跳转。

  这2方面的校验是自动化框架需要解决的基本问题,目前淘宝主站的页面自动化测试框架automan与接口测试自动化框架iTest均能较好的满足这2方面的需求。

  2. 自动化实施

  在我们目前的自动化实施中,是以功能测试的用例为蓝本,实现一个脚本,模拟手工执行的过程。

  功能测试的用例通常会是一系列的操作与一组预期结果。正常流?操作成功,页面提示操作成功,数据持久层生成记录或更新记录;异常流?操作失败,页面提示操作失败,数据持久层不更新。

  自动化脚本的写法亦是如此,一系列的操作,再作校验,符合预期?pass,不符合预期?fail。

  3. 可能存在的问题

  理想的状况是,任何操作的正常流与异常流都有UI与持久层的2层校验,这种状况下自动化脚本理论上讲能够完全覆盖功能测试的用例。

  现实与理想有一定的差距,某些模块在交互设计的时候省去了用户提示。这种情况下,无法做UI校验,2层校验无奈的退化成了1层校验:正常流?数据持久层生成记录或更新记录;异常流?数据持久层不更新。

  注意看到了,异常流不会更新持久层,也没有页面提示,与没有操作的结果是一样的。它带来的问题是异常流的用例对应的脚本无法保证完全覆盖用例,因为很可能并没有执行预期的操作。

  下面看一个例子。

  被测试的方法,都可以经过一定的抽象,成为下面的样子。

public void service(SomeRequest request, SomeReponse response) {
  // 我们的关注点而言,这是什么request和response并不重要
  // 1. request中存储了大量的参数,首先校验参数的合理性,如果参数不符合预期,不执行后面的实际操作
  if (!validateParams(request)) {
    …. // 某些操作
    return;
  }
  // 2. 执行真正的操作
  doRealAction();
}


  从测试用例的角度,我们期待的是,极少量验证参数正确性的用例在代码逻辑1处停住,多数的用例都要能走到代码逻辑2中,这样才是真正的在做功能测试,在做业务逻辑的测试。

  结合抽象过后的代码及我们的窘境,可以发现问题的所在,期待的是在代码逻辑2中走到异常流,但可能事实是直接在代码逻辑1中已经停止了执行。

  简单的分析一下原因。首先是设计上的不合理,即便交互设计是不给用户提示,但在实现中,也可以做到在response中标识明确的错误原因,接口自动化测试这种不care界面只关注流程的测试方法能很好的做到2层校验从而规避风险。其次是request中的参数格式问题,通常测试脚本在实现的时候肯定会保证参数的正确性,这个时候是可以确保在代码逻辑2中走到异常流的,但是参数格式严格依赖于开发人员的设计,如果开发人员修改了参数的格式并与原来的格式不兼容,发生了我们不愿意看到的情形了。

  4. 解决方案

  第1种解决方案,也是好的解决方案,推动开发人员修改设计与实现,总是在response中带入错误提示,这个方案需要开发人员参与,响应会很慢,通常需要几周时间。

  从上面的分析来看,期待的是在代码逻辑2中因业务逻辑的原因操作失败,实际是在代码逻辑1中因参数不符合预期停止执行。我们需要一个保证?代码正确的、确定的走到代码逻辑2中。回想一下,正常流是操作成功,持久层更新记录或生成记录,那么一个主流程的正常流的脚本pass了,可以保证代码能够正确、确定的走过了代码逻辑2。因此,第2种解决方案便出来了:只有1层校验的异常流脚本,必须要同时有一个配套的主流程的正常流的脚本,才能完整的、完全的覆盖对应的功能测试用例。

  总结,自动化测试的目的是以机器代替人工,其中一个核心的问题是如何使用自动化脚本完全的覆盖功能测试用例。从功能测试用例的角度出发,基本上都是操作再校验,因此这个问题转化为如何完善的校验。接下来分析了如何完善的校验,可能存在的问题及解决方案。

  ps:这个议题后举出的一个例子是真实的案例。在实践中遇到的问题是“出售中的宝贝”列表修改宝贝库存,修改失败也不提示错误信息,只能做数据库的校验。有8个用例,其中2个正常流能够更新成功,6个异常流更新失败,某一次项目合并主干后,8个用例里面的2个正常流总是失败,而6个异常流却总是pass,后分析是由于开发人员修改了参数格式而导致代码执行停在了代码逻辑1。