HttpUnit: 一种在 WebSphere Studio 中测试 Web 应用程序的改进方式

from:

http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0303_bhogal/bhogal.html

Kulvir Singh Bhogal (kbhogal@us.ibm.com), IBM Software Services for WebSphere 顾问, 沃斯堡,德克萨斯州


2003 年 4 月 01 日
测试。对于我们中的许多开发者来说,这个词都很令人生畏。测试的臭名很可能是因为过去测试工作的沉闷造成的。

© Copyright International Business Machines Corporation 2003. All rights reserved.

引言

测试。对于我们中的许多开发者来说,这个词都很令人生畏。测试的臭名很可能是因为过去测试工作的沉闷造成的。幸运的是,现在有了框架可以减轻测试的负担。目前,当项目经理用打印出的 Microsoft Project 日程表对您不断施压时,这种高压力项目就很容易产生代码错误。因此,彻底的测试也比过去更为重要。

但 Web 又怎样呢?

JUnit 是一个近来赢得了许多称赞的测试框架。您可以在开发过程中用 JUnit 逐渐构建测试套件。如此自动化的单元测试是极端编程(Extreme Programming,XP)方法的一个不可缺少的部分。JUnit 对于 Java 程序员来说很好用,但对于那些从事 Web 开发的程序员来说怎么样呢?HttpUnit 的开放源代码 Java API 可以帮助我们。在本教程中,我们将用 IBM® WebSphere® Studio Application Developer(以下称为 Application Developer)构建一个小 Web 站点,然后用 HttpUnit 测试我们的样本站点。

测试 Web 站点的传统(原始)方式

我承认 - 过去,我创建过带表单的小“driver”页面用来把数据提供给我想要测试的 Java servlet。我还把名-值对手工添加到了 URL 的末尾处,如 http://www.somesite.com/myPage?myVarName=myTestValue 。这两种方法都行得通。但这就像试图用一把剪刀来修剪草坪一样。必须要有一种更好的方式。

HttpUnit

与上面所说的测试方法不同,HttpUnit 不需要使用浏览器。您可以使用 HttpUnit 直接调用要测试的代码。从本质上来说 HttpUnit是模拟 Web 浏览器,并且 HttpUnit API 可以模拟浏览器的许多行为,包括:
表单提交
JavaScript
HTTP 认证
Cookie

您也可以在装入 Web 页面时用 HttpUnit API 分析返回的内容。

为什么用 HttpUnit 而不用其他选择?

由于 Web 的发展以及 Web 编程错误重重的特征,市场上出现的许多商业测试产品都用详细的 GUI 引导开发者进行测试。另一方面,开放源代码的 HttpUnit 无需许可费用,而且使用简单(您将在下面看到这一点)。正是它的简单性使它如此受欢迎。虽然没有漂亮的 GUI,但 HttpUnit Java 源代码的可用性和它的简单 API 使开发者能够创建他们自己的测试解决方案来满足特定组织的需要。用 HttpUnit 作为基础,您可以用最小的成本构建复杂的测试套件。

分解 HttpUnit

HttpUnit 可以被分为两个核心组件:
一个发送请求并接收响应的 Web 客户机
一个分析并验证响应内容的方法集

使用 HttpUnit 是不是相当于进行单元测试?

与它的名字可能暗示的相反,HttpUnit 实际上并不做单元测试。实际上,HttpUnit 更适合做功能测试或“黑箱”测试。您用 HttpUnit 写的测试将从外部查询 Web 服务器并使您能够分析接收到的响应。功能测试在 XP 方法中起着重要的作用,这种方法强调功能测试,使开发者可以获取有关系统整体状态的反馈。使用单元测试,有时会丢失大方向。在将整个站点投入到实际使用的过程中,自动功能测试可以把开发者从手工检查站点区域的繁重工作中解救出来。在 Web 环境中,有些专家认为每个请求-响应周期都是原子的,这些原子的周期可以依次被作为单独的代码单元,因此使用 HttpUnit 可以被认为是在进行单元测试。与其加进来这个哲学讨论,我们不如继续前进并开始工作!

样本应用程序

我们的样本应用程序包含一个 HTML 文件,我们在这个文件中输入将要在摄氏单位和华氏单位之间进行来回转换的温度。转换过程将由一个 servlet 执行,结果返回到一个 JSP 并显示出来。当然,我们可以在客户机端利用 JavaScript 来做所有这些工作,但使用不同的 Web 组件将会显示用 HttpUnit 进行测试的价值。


 回页首





创建测试服务器

这部分假设在您的机器上没有安装测试服务器。要在 Application Developer 中创建服务器,请打开 Server 透视图。在 Server configuration 窗格中,右键单击 Servers文件夹并选择 New => Server and server configuration。

 

在下一屏中,指定 Server name 为 TestServer 并为 Server type 选择 WebSphere Version 5.0 Test Environment 。

 

单击 Next。如果被问及是否愿意创建一个名为 Servers 的新服务器项目,请单击 Yes。

这时将会显示一个对话框,在这个对话框中您可以指定测试服务器将要侦听的 HTTP 端口。保持缺省设置 9080 并单击 Next。

 

导入项目 EAR

您可以通过 下载 tempprojectfiles.zip 来访问温度转换器(Temperature Converter)项目 EAR 文件。在 Studio 工作区中,选择 File => Import。

选择 EAR 文件的一个导入源。在下一屏中,转到您硬盘上的 EAR 文件,把您的项目命名为 TemperatureConversionProject ,然后单击 Finish。

 


 回页首





手工测试应用程序

此时,您应该能够手工测试应用程序了。启动测试服务器并让您的 Web 浏览器指向 http://localhost:9080/TempConvertHttp/TemperatureEntry.html 。这样温度转换应用程序(Temperature Conversion Application)将会出现:

 

样本结果

对这个应用程序做一下试验,看看它是如何运行的。下面的抓屏显示了如果把摄氏 98 度转换为华氏温度将会看到的结果:

 

一堂快速的科学课

下面是在华氏温度和摄氏温度之间进行来回转换的公式:C = temperature in degrees Celsius
F = temperature in degrees Fahrenheit
   



把华氏温度转换为摄氏温度: C = (F-32)*(5/9)
把摄氏温度转换为华氏温度: F = ((9/5)*C)+32

分解 TempConverterServlet

下面的代码用于 TempConvertServlet ,即转换温度的引擎。您可以从代码中看到,它获取将被转换的温度并从请求获取任务,计算结果,然后把这一结果与输入温度和任务一起返回。接下来把控制权移交给 conversionResult.jsp 。 import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet converts temperatures from Celsius to Fahrenheit or vice versa
 */
public class TempConverterServlet extends HttpServlet {
 /**
 * @see javax.servlet.http.HttpServlet#void (javax.servlet.http.HttpServletRequest,
 * javax.servlet.http.HttpServletResponse)
 */
 public void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
  String convertMe = req.getParameter("convertMe");
  double whatToConvert = Double.parseDouble(convertMe);
  System.out.println("Converting" + whatToConvert);
  double converted =0.0;
  String conversionType = req.getParameter("howToConvert");
  if (conversionType.equals("C2F"))
  {
  converted = (9*(whatToConvert)/5)+32;
  }
  else if (conversionType.equals("F2C"))
  {
  converted = (5*(whatToConvert-32))/9;
  }
  String convertedString = Double.toString(converted);
  req.setAttribute("ConversionResult",convertedString);
  req.setAttribute("ConversionSource",convertMe);
  req.setAttribute("ConversionMethod",conversionType);
  RequestDispatcher dispatcher =
  getServletContext().getRequestDispatcher("conversionResult.jsp");
  dispatcher.forward(req,resp);
 }
 /**
 * @see javax.servlet.http.HttpServlet#void (javax.servlet.http.HttpServletRequest,
 * javax.servlet.http.HttpServletResponse)
 */
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
  doGet(req, resp);
 }
}
   



使用 conversionResult.jsp 来报告结果

请看一下 conversionResult.jsp 的代码。它只是从请求对象中提取信息,这个对象我们在前面已存储在 TempConverterServlet 中了。您将看到一些用来帮助动态显示结果的嵌入式小脚本程序。

分析结果

请注意:我们将以 HTML 表形式在 JSP 中显示结果。下面您将看到一个矩阵布局的表,并且能清楚地看到如何把这张表分解为行和列。下面的矩阵中描述了一个 [i][j] 格式的表单元,其中 i 表示行而 j 表示列。请查看下面的矩阵,208.4 在第 1 行,第 2 列(行列从零开始索引)。我们将在自动测试时使用这一信息。

 


 回页首





创建您的测试 Java 项目

在 Application Developer 中,创建一个新的 Java 项目,命名为 TestHttpProject 。在 Java settings 的 Projects 选项卡中,请选中 TempConvertHttp项目。

 

添加外部 JAR

在 Libraries 选项卡中,单击 Add External JARs并指向下面的 JAR 文件: httpunit.jar、js.jar、junit.jar、servlet.jar、Tidy.jar 。所有这些 JAR 文件都在 HttpUnit 项目的 ZIP 文件中,您可以通过从 sourceforge.net下载。

 

一旦您添加好了这些 JAR,请单击 Finish。

导入您的测试类

右键单击 TestHttpProject并选择 Import => File System,然后单击 Next。请转到包含已解压缩的项目文件(这些文件原来在该项目的 ZIP 文件中)的目录,选中 TempConverterTester.java,然后单击 Finish。

 

分析 TempConverterTester

TempConverterTester 将继承类 junit.framework.TestCase 。要把我们的测试设置为 JUnit 测试,这种派生是必要的。自省被 JUnit 框架用来查找测试刚开始时所用的类中的方法。这项工作将在 TestSuite 构造函数在代码中被调用时完成: public static Test suite()
{
 return new TestSuite(TempConverterTester.class);
}
The suite static method is called in our main method with the code:
public static void main(String[] args)
{
 junit.textui.TestRunner.run(suite());
}
   



仔细检查 testConvertsCorrectlyWithServletUnit() 方法public void testConvertsCorrectlyWithServletUnit()
  {
  try
  {
  System.out.println("Starting Conversion Results Test with ServletUnit");
  ServletRunner sr = new ServletRunner();
  sr.registerServlet( "TempConverterServlet", TempConverterServlet.class.getName() );
  ServletUnitClient sc = sr.newClient();
  WebRequest request = new PostMethodWebRequest(
"http://localhost:9080/TempConvertHttp/TempConverterServlet" );
  request.setParameter("convertMe", "100" );
  request.setParameter("howToConvert","C2F");
  WebConversation wc = new WebConversation();
  WebResponse resp = wc.getResponse( request );
  String[][] tableContents = resp.getTables()[0].asText();
  assertEquals("100",tableContents[0][2]);
  assertEquals( "212.0", tableContents[1][2] );
  System.out.println("Conversion Results Test with ServletUnit Completed");
  System.out.println("----------------------------------------");
  }
  catch(Exception e)
  {
  e.printStackTrace();
  }
  }
   



让我们花点时间来分析这个方法,因为它是我们的测试的核心:ServletRunner sr = new ServletRunner();
sr.registerServlet( "TempConverterServlet",
TempConverterServlet.class.getName() );
   



我们首先实例化一个 ServletRunner 实例,ServletRunner 是 HttpUnit 附带的 ServletUnit 框架的一部分。ServletUnit 框架允许在“模拟 servlet 容器”中测试。然后我们在 ServletRunner 中注册 servlet。

指定请求参数

在 HttpUnit API 中,WebRequest 对象表示向服务器发出的请求:WebRequest request = new PostMethodWebRequest(
"http://localhost:9080/TempConvertHttp/TempConverterServlet" );
   



我们使用 WebRequest 对象的 setParameter 方法来设置参数和相应的值。request.setParameter("convertMe", "100" );
request.setParameter("howToConvert","C2F");
   



相对于上面所说的在 URL 的末尾添加名-值对而言这种方法更好。对于更大规模的测试,setParameter 方法的组织会更完善。

与服务器对话

我们与服务器真正的对话是由下面的代码执行的:WebConversation wc = new WebConversation();
WebResponse resp = wc.getResponse( request );
   



WebConversation 是 HttpUnit WebClient 类的一个实现。本质上,WebConversation 与 Web 浏览器的作用类似。WebRequest 对象表示向服务器发出的请求,而 WebResponse 对象封装应答。WebConversation 的用途要比这个过于简单的案例表现出来的多得多。WebConversation 对象可以维护高级客户机状态属性,如 cookie、相对 URL 和 frameset 属性。

分析响应

HttpUnit API 允许通过请求检查响应。当您重新调用它时,servlet 把控制权传递回 conversionResult.jsp 。如果我们的温度转换实用程序正常运行的话,摄氏 100 度将被转换为华氏 212 度。

 

如果重新调用,在生成的 JSP 中,源温度值将出现在表单元 [0][2] 中,而结果在表单元 [1][2] 中。String[][] tableContents = resp.getTables()[0].asText();
   



代码 resp.getTables()[0] 允许我们访问结果页面中我们的第一个(也是唯一一个)表。使用 HttpUnit API,我们可以从结果页面中以二维字符串阵列形式提取表内容。

验证结果

我们将验证我们的应用程序是用下面的代码来直接转换温度:assertEquals("100",tableContents[0][2]);
assertEquals( "212.0", tableContents[1][2] );
   
这里,我们向所提供的 JUnit 中输入所需的内容。我们使用它的 assertEquals 方法来确认单元内的内容与我们所期望的一致。当运行 TempConverterServlet 类时,您将在控制台看到:
    

您可能想玩一下 TempConverterServlet 代码,故意改变转换方法来看一下测试将如何反应。下面是一个出错测试结果的抓屏:


结束语

本文描述了 HttpUnit,并向您介绍了一个应用 HttpUnit 的样本应用程序。您了解了怎样用 HttpUnit、JUnit 和 ServletUnit 来自动化 Web 应用程序的测试。按照 XP 的思想,黑箱测试和单元测试对于创建稳定的 Web 应用程序都是至关重要的。HttpUnit、JUnit 和 ServletUnit 的开放源代码 API 可以被用于创建功能齐全的自动测试解决方案,从而使您可以根据自己企业的 Web 站点测试需求来定制测试。


相关信息
关于更多信息,请参阅 HttpUnit 主页。
关于 Cactus(Apache 软件基金会(Apache Software Foundation)提供的一个开放源代码工具,用于对服务器端的 Java 代码进行单元测试)的更多信息,请参阅文章 Developing and Unit Testing with Open-Source Apache Cactus Framework Tools in WebSphere Studio。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值