总体设计
该框架使用了 MVC 的设计思想,采用 J2EE 的 web 技术作为表现层,使用 Struts 这个流行的 JAVA 框架作为控制层,采用 hibernate 与 JDBC 相结合的方法处理数据持久化,主要的工作放在逻辑层,包括对回归测试 request 的任务分析,生成 Configuration 列表,Configuration 运行期的任务调度,多线程的 Configuration 测试流程以及每个 Configuration 的自动执行。
测试框架采用 IBM Websphere Application Server 作为服务器容器,采用 IBM DB2 作为数据库产品,采用由 IBM 开发的软件测试自动化框架(Software Testing Automation Framework,简称 STAF)以及其执行引擎(STAf eXecution engine,简称 STAX)作为框架内部的分布式调用平台。
图 1. 体系结构图
项目拓扑结构
本测试框架应用于 DB2 JCC 的测试场景中,需要一台应用服务器作为框架的支撑,一台数据库服务器作为数据持久化的容器,这两者可以使用同一台服务器。在具体测试时,还需要若干台 DB2 Server 和 DB2 Client,都可以由虚拟机来构建,以达到最优化测试资源配置和自动化的目的。同时,还需要一些项目相关的资源,如存放测试软件安装程序的 FTP 站点(这里以 DB2 为例)等。
图 2. 项目拓扑图
回页首
前台设计与实现
基于 Struts 的表现层 mvc 设计
Struts 是一个 JAVA 世界非常流行的表现层 MVC 框架,对于 web 开发表现层的各个方面都有很好的细节处理,如表单验证、请求分发等。我们的测试框架便采用了 Struts,下面给出一个测试请求的提交页面,用户可以定制自己测试的属性,选择测试版本、期望报告时间等,易于使用。
图 3. 测试任务提交页面
使用 Filter 控制用户权限
我们的测试框架面对的用户主要有多种角色。以开发人员和测试人员为例,开发人员通过 web 提交任务,并进行一些任务信息的管理和查看;测试人员权限更大一些,需要能完全掌握整个系统的运行状况,在有必要的时候进行人工干预。因此,系统需要对用户进行权限控制。
Servlets Filter 是 Servlet 2.3 规范中新增加的,它是截取用户从客户端提交的请求,在还没有到达需要访问的资源时运行的一个类。它操纵来自客户端的请求,在资源还没有发送到客户端前截取响应,并处理这些响应。
因此,Filter 非常适合做用户权限的控制和过滤。项目中使用了两个 Filter,一个用于登录的验证,在 Filter 中检查 Session 的状态,控制用户登录情况。另一个用于权限的验证,通过给用户的角色分配不同权限的 URL 列表,在 Filter 中进行 URL 的检查,可以达到控制权限的目的。
结合 JDBC 和 Hibernate 实现数据层持久化
Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate 内容简单,十分灵活,但数据持久化的效率比 JDBC 要低。如果 JDBC 的代码写的非常优化,那么 JDBC 架构运行效率最高,但也会带来大量重复的数据库编程。
结合上述的特点,我们采取的策略是:使用 Hibernate 作为 OR 映射的框架,这能大大加快开发进度;在对性能要求较高的场合,例如测试资源匹配、状态监控等,使用 JDBC SQL 来操作,当然 JDBC 的 Sesstion 是通过 Hibernate 来获取的。
回页首
控制层的并发处理
Test Configuration 的工厂实现
用户提交的测试任务可能是较为复杂,并不是实际测试中的测试执行单元,实际测试的资源分配是根据最小测试执行单元的。我们的框架需要能分析任务的复杂程度,并依据测试规则将其分解成我们需要的最小执行单元。
我们的框架中实现了一个 Configuration 工厂,这个工厂能够对用户测试请求进行解析,主要包含两个方面:一,对测试任务进行 Configuration 的分解;二、排除不符合测试规则的无效因素。最后生成一个 Configuration 的列表。
图 4. Configuration 解析列表页面
基于 FCFS 和修正优先级的 Configuration 调度
我们的框架主要是面向测试人员和开发人员,即使访问量不是很大,但是受限于测试所需要的各种测试资源,仍然需要一个 Configuration 调度程序来管理,以实现尽可能的多任务的并发和尽可能高的资源利用率。
当一个测试任务到来的时候,依据测试任务的复杂度和测试结果提交日期的紧迫程度,系统会为测试任务分配一个优先级;如果优先级相等,依据 FCFS(先来先服务)规则进行测试资源的匹配。同时,系统会维护一个 Configuration 等待队列,用于存放暂时无法得到运行的 Configuration。这个队列中 Configuration 的优先级是不断动态修正的,例如,当一个 Configuration 匹配测试资源成功得到运行后,与其同组的 Configuration 的优先级会被调低,以达到测试资源的平均分配。
基于 Multi-thread 的 Kickoff
每一个获得测试资源得到执行的 Configuration 都必须在一个单独的线程里执行,这是毋庸置疑的,否则无法实现并发的执行任务。执行线程需要处理一个 Configuration 测试过程中所有步骤,比如准备测试环境、下载 Build、准备驱动程序等。其中很多个步骤都是需要花较长时间,在这段时间内,没有理由让线程仍然占用 CPU 资源。
我们在系统中维护一个资源锁列表,每一个资源锁对应一个线程。当线程发出一个需要较长时间才能返回的 STAF 命令时,线程会释放相应的锁,处于资源阻塞状态;当命令执行完成后,会异步的更新锁状态,同时返回执行的结果信息。然后 Configuration 执行线程得到执行,读取返回的结果信息,判断是否继续走下一步的测试步骤。