自动测试可以节省重复执行相同测试步骤的 时间和精力。本文将介绍 jWebUnit,这是一组 Java 类,用于为 Web 应用程序开发测试用例。jWebUnit 是一个开源项目,可以在 BSD 许可下免费获得。我将介绍如何下载 jWebUnit 库、配置 Eclipse 平台来开发 jWebUnit 测试用例,以及如何构建一个示例测试用例。

jWebUnit 简介
jWebUnit 以 HttpUnit(一个进行 Web 应用程序自动测试的 Java 库)和 JUnit 单元测试框架为基础(请参阅 参考资料)。 jWebUnit 提供了导航 Web 应用程序的高级 API,并组合了一组断言,用它们来验证链接导航、表单输入项和提交、表格内容以及其他典型商务 Web 应用程序特性的正确性。 jWebUnit 以 JAR 文件形式提供的,可以很容易地将它插入大多数 IDE 中,jWebUnit 也包含其他必要的库。

用 HttpUnit 进行测试
对 Web 应用程序自动进行测试意味着跳过 Web 浏览器,通过程序来处理 Web 站点。首先,我要介绍 HttpUnit(JWebUnit 的构建块之一)是如何简化这项工作的。HttpUnit 可以模拟帧、JavaScript、页面重定向 cookie,等等。在将 HttpUnit 用于 JUnit 时,它可以迅速地对 Web 站点的功能进行验证。

清单 1 显示了一个用 HttpUnit 编写的测试用例,它试图单击 HttpUnit 主页上的“Cookbook”链接:

清单 1. 单击 HttpUnit 主页上 Cookbook 链接的 HttpUnit 代码

            1 public class HttpUnitTest {
            2  public static void main(String[] args) {
            3    try {
            4      WebConversation wc = new WebConversation();
            5      WebRequest request =
            new GetMethodWebRequest("http://httpunit.sourceforge.net/index.html");
            6      wc.setProxyServer( "your.proxy.com", 80 );
            7      WebResponse response = wc.getResponse(request);
            8      WebLink httpunitLink =
            response.getFirstMatchingLink(WebLink.MATCH_CONTAINED_TEXT,"Cookbook");
            9      response = httpunitLink.click();
            10      System.out.println("Test successful !!");
            11    } catch (Exception e) {
            12      System.err.println("Exception: " + e);
            13    }
            14  }
            15 }
            

清单 1 中的代码用 your.proxy.com (第 6 行)连接 Internet。如果存在直接 Internet 连接,那么可以把这个语句注释掉。第 8 行的语句在页面中搜索包含文本 Cookbook 的 Web 链接。第 9 行的语句用于单击这个链接。如果找到链接,那么用户会看到 Test Successful !! 这条消息。

用 jWebUnit 进行的测试更简单
清单 2 的测试用例用 jWebUnit API 执行和清单 1 相同的任务:

清单 2. 单击 HttpUnit 主页上 Cookbook 链接的 jWebUnit 代码

            1 public class JWebUnitTest extends WebTestCase{
            2  public static void main(String[] args){
            3    junit.textui.TestRunner.run(new TestSuite(JWebUnitTest.class));
            4  }
            5  public void setUp(){
            6    getTestContext().setBaseUrl("http://httpunit.sourceforge.net");
            7    getTestContext().setProxyName("webproxy.watson.ibm.com");
            8    getTestContext().setProxyPort(8080);
            9  }
            10  public void testSearch(){
            11    beginAt("/index.html");
            12    clickLinkWithText("Cookbook");
            13  }
            14 }
            

如果没注意清单 2 中特定于 JUnit 的代码,那么您可以看到,测试用例现在变得相当整洁、简练。需要查看的重要的行是第 6 行、第 11 行和第 12 行。在第 6 行,基本 URL 被设置到 HttpUnit 的主页中。第 11 行用相对路径 /index.html 连接站点。第 12 行用于单击页面上具有文本 Cookbook 的链接。如果链接有效,那么 JUnit 会报告成功;否则,JUnit 会报告异常。

jWebUnit API:进一步观察
每个 jWebUnit 测试的核心都是 net.sourceforge.jwebunit.WebTestCase 类,它代表测试用例。每个测试用例都必须是从这个类扩展而来。(net.sourceforge.jwebunit.WebTestCase 类本身则是从 junit.framework.TestCase 类扩展而来的,它在 JUnit 中代表测试用例。) 表 1 描述了这个类的一些常用方法:

表 1. net.sourceforge.jwebunit.WebTestCase 类的重要方法
方法 说明
public TestContext getTestContext() 得到测试用例的上下文。可以用它访问像地区、基本 URL 和 cookie 之类的项目
public void beginAt(String relativeURL) 在相对于基本 URL 的 URL 处开始对话
public void setWorkingForm(String nameOrId) 与指定的表单开始交互。如果当前页面只有一个表单,就不需要调用这个方法
protected void submit() 提交表单 —— 等同于单击表单的 提交 按钮
public void gotoFrame(String frameName) 激活命名帧

另一个重要的类是 net.sourceforge.jwebunit.TestContext。它为测试创建上下文。可以用这个类来处理像 cookie、会话和授权之类的信息。表 2 显示了这个类的一些重要方法:

表 2. net.sourceforge.jwebunit.TestContext 类的重要方法
方法 说明
public void addCookie(String name, String value) 向测试上下文中添加 cookie。在 HttpUnitDialog 开始时,添加的 cookie 被设置到 WebConversation
public void setResourceBundleName(String name) 为测试上下文设置一个使用的资源绑定。用于按照 WebTester 中的键查找期望的值
public void setProxyName(String proxyName) 为测试上下文设置代理服务器名称
public void setBaseUrl(String url) 为测试上下文设置基本 URL

下载 jWebUnit,在 Eclipse 中配置 jWebUnit
jWebUnit 是用纯 Java 代码实现的,所以可以以 JAR 文件的形式获得它 (请参阅 参考资料,从中获得下载链接)。在完成下载之后,请按以下步骤在 Eclipse 平台上配置 jWebUnit 库:

  1. 把下载的文件 jwebunit-1.2.zip 释放到临时目录中(假设是 C:\temp)。
  2. 在 Eclipse 中创建新 Java 项目,将其命名为 jWebUnit。
  3. 右击 Package Explorer 视图中的 jWebUnit 项目,然后选择 Properties
  4. 单击 Java Build Path。单击 Libraries 标签中的 Add External JARs
  5. 浏览到 C:\temp\jwebunit-1.2\lib 目录,选择这个目录中的所有 JAR 文件。
  6. 单击 OK

现在可以在 Eclipse 中的 jWebUnit 项目下开发 jWebUnit 测试用例了。

构建示例应用程序
现在就可以查看 jWebUnit API 的实际应用了。我将带您研究一个示例应用程序,帮助您更好地理解 jWebUnit 的真正威力。这个应用程序是一个测试用例,用于打开一个 Google 搜索页面并搜索文本 HttpUnit。应用程序需要测试以下场景:

  • 打开 Google 主页 http://www.google.com。

  • 确定该页包含一个名为 q 的表单元素。(在 Google 的主页上,名为 q 的文本框是接受用户查询输入的文本框。)应用程序用这个元素输入搜索参数。

  • 在搜索文本框中输入字符串 HttpUnit Home,并提交表单。

  • 获得结果页,并确定该页面包含的链接中包含文本 HttpUnit Home

  • 单击包含文本 HttpUnit Home 的链接。

现在测试场景已经就绪,可以编写 Java 应用程序,用 jWebUnit 实现这些需求了。

第一步是声明一个从 WebTestCase 扩展而来的类,如清单 3 所示:

清单 3. 声明测试用例类

            public class GoogleTest extends WebTestCase {
            static String searchLink = "";
            }
            

正如我在前面提到过的,jWebUnit 要求每个测试用例都是从 WebTestCase 中扩展而来的。searchLink 保存传入的搜索参数。这个值以命令行参数的形式传递给测试用例。

下一步是声明入口点 —— main() 方法,如清单 4 所示:

清单 4. main() 方法

            public static void main(String[] args) {
            searchLink = args[0];
            junit.textui.TestRunner.run(new TestSuite(GoogleTest.class));
            }
            

main() 方法调用 junit.textui.TestRunner.run() 执行 JTest 测试用例。因为需要运行 GoogleTest 测试用例,所以,作为参数传递给 run() 方法的测试套件采用 GoogleTest.class 作为参数。

接下来,JTest 调用 setUp() 方法来设置基本 URL 和代理,如清单 5 所示:

清单 5. 设置

            public void setUp() {
            getTestContext().setBaseUrl("http://www.google.com");
            getTestContext().setProxyName("proxy.host.com");
            getTestContext().setProxyPort(80);
            }
            

清单 5 把基本 URL 设置为 http://www.google.com。这意味着测试用例的启动是相对于这个 URL 的。下面两个语句设置连接到 Internet 的代理主机和代理端口。如果是直接连接到 Internet,那么可以忽略代理设置语句。

现在开始浏览站点并输入搜索参数。清单 6 显示了访问 Web 页面,然后测试所有场景的代码:

清单 6. 测试所有场景

            public void testSearch() {
            beginAt("/");
            assertFormElementPresent("q");
            setFormElement("q", "HttpUnit");
            submit("btnG");
            assertLinkPresentWithText(searchLink);
            clickLinkWithText(searchLink);
            }
            

清单 6 的代码连接到基本 URL,并相对于 / 开始浏览。然后它断定页面中包含一个名为 q 的表单元素 —— q 是 Google 主页上查询输入文本框的名称。下一条语句用值 HttpUnit 设置名为 q 的文本框。再下一条语言提交表单上名为 btnG 的提交按钮。(在 Google 的主页上,名为 btnG 的按钮是标签为 Google Search 的按钮。)表单是在这个对话中提交的,下一页列出搜索结果。在结果页面上,代码首先检查是否有一个链接的文本是 HttpUnit Home。如果该链接不存在,那么测试就以 AssertionFailedError 失败。如果该链接存在,则测试执行的下一个操作是单击链接。

运行示例应用程序
现在把示例应用程序投入使用当中:

  1. 下载示例应用程序 j-webunitsample.jar (请参阅 下载)。

  2. 在一个目录中解压缩 j-webunitsample.jar。例如,如果把它释放到 C:\temp 中,那么就要把源文件和类文件放在 C:\temp\com\jweb\test 中,而 setclasspth.bat 则放在 C:\temp 中。

  3. 编辑 setclasspath.bat:设置 JAR_BASE 指向包含所有必需 JAR 文件的目录。例如,如果在 C:\temp 中释放 jwebunit-1.2.zip 文件,那么将 JAR_BASE 设置为 C:\temp\jwebunit-1.2\lib。

  4. 打开命令行提示符,切换到 C:\temp 目录。

  5. 执行 setclasspath.bat。这会设置执行测试用例所需的 CLASSPATH

  6. 用命令 java com.jweb.test.GoogleTest "HttpUnit Home" 运行应用程序。

示例输出
在执行了测试用例之后,会在命令行输出一个测试用例报告。如果测试失败,报告看起来如清单 7 中所示:

清单 7. 带有断言失败的输出

            C:\temp>java com.jweb.test.GoogleTest "HttpUnit Hwee"
            .F
            Time: 5.338
            There was 1 failure:
            1) testSearch(com.jweb.test.GoogleTest)junit.framework.AssertionFailedError: Link
            with text [HttpUnit Hwee] not found in response.
            at net.sourceforge.jwebunit.WebTester.assertLinkPresentWithText(WebTester.java:618)
            at net.sourceforge.jwebunit.WebTestCase.assertLinkPresentWithText(WebTestCase.java:244)
            at com.jweb.test.GoogleTest.testSearch(GoogleTest.java:36)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at com.jweb.test.GoogleTest.main(GoogleTest.java:19)
            FAILURES!!!
            Tests run: 1,  Failures: 1,  Errors: 0
            

正如在清单 7 中可以看到的,可以用 HttpUnit Hwee 作为参数来执行测试用例。这个测试用例遇到断言的地方会失败,因为结果页面中不包含带有这个文本的链接。由此也就产生了junit.framework.AssertionFailedError

清单 8 执行时用 HttpUnit Home 作为参数。测试用例找到一个带有这个文本的链接,所以测试通过了:

清单 8. 成功测试的输出

            C:\temp>java com.jweb.test.GoogleTest "HttpUnit Home"
            .
            Time: 6.991
            OK (1 test)
            

结束语
本 文通过讨论 jWebUnit 框架的一些突出特性和最重要的类,介绍如何用它创建简洁的测试用例,让您对 jWebUnit 框架有一个认识。jWebUnit 还有更多特性可以用在测试用例中。它支持测试 Web 页面中的链接行数。可以对字符串、表或者带有指定标签的表单输入元素是否存在于页面上进行断言。此外,jWebUnit 还可以处理 cookie (例如断言存在某个 cookie、删除 cookie 等。)测试可以对某个文本之后出现的特定文本的链接进行单击。 如果想为 Web 应用程序构建快而有效的测试用例,jWebUnit 可能是您最好的朋友。