Java是一种高级语言,您可以用Java开发出精美的网站,强大的程序,也可以使用基于Java的自动化测试工具将自己从纷繁复杂的手工测试中解脱出来。对比于亦步亦趋的手工测试,自动化测试显然更加方便,也更有效率。但是如同大多数基于Java的工程一样,基于Java的测试系统同样不可避免的会使用到许多现今流行的框架,比如JUnit,TestNG,以及STAF等。毫无疑问,合理的使用这些框架会给测试系统的开发带来极大帮助,因为站立在巨人肩上,你总能看得更远一些。
下面先对一些测试框架进行简单说明,再结合具体测试用例说明我们是如何根据各个框架的特点进行工作的。
JUnit: 顾名思义,JUnit是一个基于Java语言的单元测试框架。在软件测试的发展进程中,JUnit的出现具有举足轻重的意义,有人甚至说JUnit的出现开辟了软件测试的新纪元。有趣的是,JUnit是在一次长途飞行旅程中完成的,以至于许多年以后,JUnit的作者之一Kent Beck说:“我想我们是在飞机上写程序。”
不过如同所有软件产品一样,JUnit也并非一蹴而就,它的发展同样是一个漫长的历史,在这个历史过程中,JUnit日渐强大,日臻完善,它让软件测试变得更加方便,更加灵活,而且更加稳定。但是随着时光的流逝,JUnit的局限性也逐渐显现出来。其中最重要的一点,就是JUnit将自己定位于单元测试框架,这使得它在系统测试、分布式测试、依赖测试、数据驱动测试等方面无法满足软件开发商日新月异的需求。在这种情况下,TestNG应运而生。
TestNG: TestNG是一种基于系统测试的测试框架,它通过添加测试分组、测试参数以及测试单元之间的依赖性等手段,使开发人员可以编写出更加灵活、更加强大的测试脚本。由于本文提到的测试案例涉及到TestNG,所以在此处我们先举些例子,使读者对TestNG有个大致了解。
请看下面这段代码:
package example1;
import org.testng.annotations.*;
public class SimpleTest {
@BeforeClass(groups = { "setup" }, enabled=true)
public void setUp() {
// code that will be invoked when this test is instantiated
}
@Test(groups = { "fast" }, dependsOnGroups={ "setup" }, timeOut = 2000000)
public void aFastTest() {
System.out.println("Fast test");
}
@Test(groups = { "slow" })
public void aSlowTest() {
System.out.println("Slow test");
}
}
注意TestNG的标签均是以@开始,@BeforeClass意味着被此标签修饰的方法将在该Class所有测试方法执行前被调用,而@Test修饰的方法即为测试方法。
通过对标签的了解,我们知道在SimpleTest类中的三个方法,执行顺序有可能是setUp()->aFastTest()->aSlowTest(),aFastTest()与aSlowTest()执行的先后顺序我们无法确定,然而可以肯定的是,setUp()一定会先于其余两个方法执行。这就是TestNG系统的测试依赖性。
除了@BeforeClass与@Test之外,TestNG还有大量的标签,如:@BeforeSuite, @AfterSuite, @BeforeTest, @AfterTest, @BeforeGroups, @AfterGroups, @BeforeClass, @AfterClass, @BeforeMethod, @AfterMethod, @DataProvider, @Factory, @Listeners, @Parameters, @Test等,具体意义,有兴趣的读者可以参考TestNG的官方网站http://testng.org/,此处不再一一赘述。
另外请注意在每个标签中,我们均可以指定一些对应的些参数,如groups, dependsOnGroups, timeOut等参数,从而改变测试的执行环境,执行顺序等,这也是TestNG灵活性的具体体现。
STAF: 在许多自动化测试系统中,STAF已经得到了广泛的应用。STAF是Software Testing Automation Framework的缩写,它是一个开源软件,你可以从http://staf.sourceforge.net/下载STAF。
STAF是一种分布式远程调用体系,支持跨平台和多语言的自动化测试框架。从某个角度而言,STAF就象一个middleware,它将多台互不相关的测试机组织为一个整体,共同进行测试。与许多middleware一样,STAF的用户同样可以根据需求自行编写Service。然而编写Service的工作量通常较大,所以一个更简便的办法是只编写一个启动程序脚本的服务StartProc,而具体功能可以放在脚本中实现。比如我们要想在HostA中获取HostB的日期时间等信息,可以编写脚本程序GetTime.sh,将其存放于HostB,然后通过在HostA执行命令:staf HostB StartProc start GetTime
从而根据命令执行结果,分析出HostB的日期时间信息。
下面就一个防火墙的测试案例来说明我们是如何利用TestNG和STAF框架来组织自动化测试系统的。
请看这幅图:
这是一个测试防火墙的示例,在这个示例中分布有如下的测试机:
Manager: 服务器,用于管理自动化测试系统。它负责向每台测试机发出指令,并根据从测试机返回的数据判断测试是否成功。所有具体的测试代码以及必要的测试数据均存放在Manager上。在软件系统架构的上层,Manager利用TestNG框架决定系统测试的分布环境、测试依赖性以及执行顺序等,在系统的下层,Manager通过STAF向分布于网络中的不同测试机分别发送指令。
Configure PC: 置于防火墙内网的PC,可以访问防火墙配置网页,完成对防火墙的配置操作。
Inner PC: 置于防火墙内网的PC,用于发送数据包或监控接收到的数据包
DMZ PC: 置于防火墙DMZ区的PC,用于发送数据包或监控接收到的数据包
Outer PC: 置于防火墙外网的PC,用于发送数据包或监控接收到的数据包
可以看出,Configure PC是一台相对特殊的PC,它仅仅负责对Firewall的配置。在自动化测试过程中,我们总是需要不断改变Firewall的配置,从而针对不同的feature进行测试。Configure PC所要做的,就是接收到Manager的配置指令及配置参数,其后再通过配置界面对Firewall进行操作。这里我们可能会使用到Ruby/Watir、Selenium或AutoIT等工具编写的脚本进行网页操作,但同Shell类似的,只需准备好相应脚本就可以了,至于Selenium等工具的说明,此处不再赘诉。
另外需要注意的是,不论是在Manager还是在测试机上都要安装好STAF。这样Manager才能够通过STAF对其余各台测试机发出指令,使其协同工作。例如,对于检查防火墙过滤特性的测试,我们可能会按照如下步骤进行测试:
1) Manager通过STAF向Configure PC发出命令,要求Configure PC对Firewall进行配置(Configure),并将配置参数传递给Inner PC
2) Configure PC接收到Manager发出的配置指令及参数后,调用预先编写好的脚本程序(如Configure.rb)对防火墙进行配置,并将配置结果返回给Manager
3) Manager向Inner PC发出指令,要求Inner PC对网络数据进行监控
4) Inner PC调用脚本程序(如Monitor.pl)监控网络端口
5) Manager向DMZ PC发出指令,要求DMZ PC对网络数据进行监控
6) DMZ PC调用脚本程序(如Monitor.pl)监控网络端口
7) Manager将准备好的数据包(Datagram.dat)传送至Outer PC
8) Manager向Outer PC发出指令,命令Outer PC将Datagram.dat的数据发送至Inner PC
9) Outer PC根据Manager的指令,调用脚本Send.pl发送Datagram.dat中的内容
10) Manager从Inner PC中取回Inner PC所监控到的数据
11) Manager从DMZ PC中取回DMZ PC所监控到的数据
12) Manager将从Inner PC与DMZ PC中取得的数据与预先期望的数据进行比较,确定测试是否成功
图示如下:
可以看到,所有的操作指令均通过Manager发出,而不同的测试机将根据指令完成具体操作。Manager不必关心操作是怎样完成的,而测试机也不必关心测试的具体流程,每台机器相对独立,而又协同工作。这样做有很多好处,一方面当测试出现错误时,很容易定位错误发生的原因,另一方面,当系统需要扩充新的功能或新的测试案例时,对代码的修改仅会集中于某些具体的模块,而不会对其余模块,或整个系统照成冲击,这就很好的实现了系统的可扩充性和可移植性。
另外由于STAF可以运行于不同的操作系统中,我们也可以编写不同版本的脚本,如在Windows中,我们可以使vbscript, jscript,而在Linux下使用shell,从而实现自动化测试系统的跨平台。也就是说,Inner PC的操作系统可以是Linux而Outer PC可以是Windows,这样测试系统的适应性就得到了很好的体现。
此外补充说明一点,有一些数据必须在测试之前预先准备好,如Firewall的配置参数、datagram.dat文件、测试期待结果等。这些数据可以根据不同的测试目的加以组织,并在测试框架中利用TestNG对数据驱动的支持,进行各种各样的测试,从而使被测试软件更加稳定,更加完善。
通过上面的说明,不难分析出自动化测试系统的软件层次结构,如下图所示:
整个系统分为五个大的层次,从上至下依次为Test层、High Lib层、Low Lib层、STAF服务层,以及脚本层,其中High Lib与Low Lib的区别是Low Lib只提供简单的功能封装,在Low Lib提供的函数中不存在任何逻辑关系,而High Lib的内容面向测试,已然有了更加明确的逻辑性。
在这个系统中,仅就上层而言,测试系统以TestNG作为框架,充分利用了TestNG面向系统测试的特点,使测试更加灵活,而在下层而言,系统却是以STAF作为框架,从而实现了分布式、跨平台的功能。所以,与所有基于Java的系统一样,构建Java自动化测试系统的一个重要原则就是,合理的利用现有的Java框架及插件,“假舆马者,非利足也,而致千里;假舟楫者,非能水也,而绝江河”,正是这个道理。