 | 级别: 中级 Donald Vines, 执行 IT 架构师, IBM
2008 年 10 月 21 日
本文向您介绍用于 SOA 环境的测试驱动的开发理论。本文将向您说明如何为 SDO 数据映射编写测试用例,并在发布这些数据映射以供其他 SCA 模块使用之前,提供用于编写测试用例和使用 Junit、Cactus 及 IBM WebSphere Integration Developer 执行这些用例的逐步说明。
来自 IBM WebSphere Developer Technical Journal。
引言
在软件工程方面,两个最近的重大变化是对测试驱动的开发和持续集成的使用日益增加。作为转向敏捷软件开发方法的一部分,这些实践已在基于 Java™ 的传统应用程序开发中使用了许多年,最近开始用于 SOA 解决方案的开发。
为此,一篇最近的 developerWorks 文章描述了 IBM WebSphere Integration Developer V6.1 的一个新功能,该功能使您能够创建测试用例,并且只需单击一个按钮即可在无人参与的情况下运行它们。另一个文章系列阐述了如何使用 JUnit 和 Cactus 来测试服务组件体系结构(Service Component Architecture,SCA)组件、BPEL 组件和人工任务。这些文章对在 SOA 环境中工作的所有 Java 开发人员都非常有帮助。为了补充那些资源,这个由两部分组成的文章系列将研究两个同等重要的附加主题:
-
数据映射的单元测试在 SOA 项目的早期阶段中极其有用。测试数据映射对于不成熟的服务接口(其中数据要么还没有很好地建立,要么不稳定)来说是必需的,并且对于较成熟的服务接口也非常有用。这些测试将使您能够不必太关心重构数据类型。您可以做出一些更改,重新测试映射,然后重新测试使用这些映射的模块。
-
持续集成是每天运行多次的完全自动化和可再现的构建(包括测试),是用于传统应用程序并得到广泛认可的开发实践。要对 SOA 环境应用这种敏捷开发实践,您需要能够作为定期计划的集成构建的一部分执行单元测试。这是在诸如 WebSphere Integration Developer 等集成开发环境 (IDE) 之外进行的,因此一般需要通过 Ant 运行单元测试。
本文向您说明如何独立于使用数据映射的 SCA 模块对数据映射进行测试。通过使您能够在发布库以供模块使用之前对库进行测试,数据映射测试对在共享库中定义公共数据类型和数据映射的标准实践形成了补充。您甚至可以在创建任何模块之前对库进行测试。这与测试驱动的开发实践是一致的。
第二部分将介绍如何在 SOA 环境中使用持续集成,使用诸如 Ant 等自动化构建工具来运行单元测试,生成测试报告,并在测试失败的情况下向开发人员发送电子邮件。
对数据映射进行单元测试
为了了解如何测试数据映射,请考虑以下场景:
可以看出,上述映射相当简单,逐个字段的映射是相对简单的。然而,对于大型业务对象,映射可能相当复杂,辨别属性彼此间的映射通常变得非常困难。创建数据映射可能是非常繁琐且很容易出错的任务,从而突出了重复测试的重要性。
要测试上述数据映射,您通常要编写两个 JUnit 测试用例。对于此示例场景,为您提供了代码示例以供下载。该示例代码在一个项目交换文件中,您可以将该文件导入 WebSphere Integration Developer V6.1 工作区。导入以后,打开 Business Integration 透视图查看三个示例项目:
-
L_AddressCleansingService:此库具有用于组合应用程序的数据类型和数据映射,并将由构成 SOA 解决方案的模块重用。
-
T_AddressCleansingService:此模块用于测试数据映射,并将仅部署到测试环境中的 IBM WebSphere Process Server。它不是 SOA 解决方案的一部分。
-
T_AddressCleansingServiceJUnitWeb:此动态 Web 项目包含了将在 WebSphere Process Server 容器中执行的 Junit 测试用例。它是 T_AddressCleansingService 测试模块的一部分。
此场景假设该库的数据类型和映射已经存在,因此本文将不介绍如何创建它们。您可以查看该库以了解它们的定义。有关如何创建数据映射的信息,您还可以查看这个 WebSphere Integration Developer 指导教程。
本文的其余内容将研究用于测试数据映射的三个大致步骤:
-
创建测试模块和 Web 项目
-
创建测试用例和数据映射
-
运行测试用例
下面几个部分将详细描述这些步骤。
1. 创建测试模块和 Web 项目
对于此步骤,您可以选择按照以下说明操作或下载并导入项目交换文件,以便能够使用所提供的测试模块和 Web 项目。如果您选择后者,请向前跳到步骤 2。
要创建测试模块,请执行以下步骤:
-
在 WebSphere Integration Developer 的 Business Integration 透视图中,打开 Business Integration 视图。请单击右键,然后选择 New => Module。在 New Module 对话框中,输入名称 T_AddressCleansingService,然后单击 Finish。
-
要创建动态 Web 项目,请切换到 J2EE 透视图。右键单击 T_AddressCleansingServiceApp 并选择 New => Dynamic Web Project。在 New Dynamic Web Project 对话框中,输入 T_AddressCleansingServiceJUnitWeb 并单击 Finish。
-
下一步,创建测试模块与包含有要映射的数据类型和要测试的数据映射的库之间的关联。为此,请切换到 Business Integration 透视图。选择 T_AddressCleansingService 并双击打开 Dependency 编辑器。展开 Libraries 并使用 Add 功能添加 L_AddresCleansingService。
-
接下来,您需要将 Log4J、Junit 和 Cactus 框架添加到测试模块。为此,将以下库添加到 T_AddressCleansingServiceJUnitWeb 项目的 web-inf\lib 文件夹:
-
最后,您需要将 Cactus Servlet 定义添加到 Web 应用程序中的 web.xml 文件。为此,请剪切清单 1 中的代码,并将其直接粘贴到动态 Web 应用程序部署描述符中的现有描述和欢迎文件之间:
清单 1
<display-name>T_AddressCleansingServiceJUnitWeb</display-name>
<servlet>
<servlet-name>ServletRedirector</servlet-name>
<servlet-class>
org.apache.cactus.server.ServletTestRedirector
</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>value1 used for testing</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>ServletTestRunner</servlet-name>
<servlet-class>
org.apache.cactus.server.runner.ServletTestRunner
</servlet-class>
</servlet>
<servlet-maping>
<servlet-name>ServletRedirector</servlet-name>
<url-pattern>/ServletRedirector</url-pattern>
</servlet-maping>
<servlet-maping>
<servlet-name>ServletTestRunner</servlet-name>
<url-pattern>/ServletTestRunner</url-pattern>
</servlet-maping>
<welcome file list> |
2. 创建测试用例和数据映射
下一步,您将为 Address_To_AddressCSV 数据映射编写测试用例。您的测试用例将填充一个输入的 Address 对象,调用该映射以产生输出 AddressCSV 对象,然后将最终获得的 AddressCSV 对象与预期的结果做比较。如果它们相等,则认为测试成功;如果它们不相等,则测试失败。(所包括的项目交换文件还包含一个用于 AddressCSV_To_Address 映射的单元测试用例。)
创建单元测试涉及到以下步骤:
-
创建测试用例
典型的 JUnit 编程模型通过扩展 JUnit 提供的 TestCase 类创建测试类。Cactus 框架是 JUnit 的扩展,Junit 使您能够在一个容器中运行单元测试。由于您是在使用 Cactus 框架,您将扩展 Cactus 测试类 org.apache.cactus.ServletTestCase。为此,请执行以下操作:
- 转到 Web 透视图中的 Project Explorer 视图,展开 Dynamic Web Projects => T_AddressCleansingServiceJUnitWeb => Java Resources => JavaSource。
- 右键单击 Java Source,并选择 New => Package 以创建适当的包。右键单击该包,选择 New => Class 以创建类,并输入如下代码:
清单 2
package com.ibm.issw.service.addresscleansing.test;
import org.apache.cactus.ServletTestCase;
public class AddressCleansingServiceTest extends ServletTestCase { |
-
编写 setup() 和 teardown() 方法
JUnit 框架为您提供了相关方法,您可以实现这些方法来为测试用例设置环境,并在运行测试用例以后销毁该环境。其中的事件序列如下:调用 setUp(),调用 testxxx() 方法,调用 tearDown()。该测试类中的每个 testXXX() 方法都将发生此事件序列。清单 3 显示了示例 setUp() 和 tearDown() 方法。
清单 3
private DataObject expectedAddress;
private String expectedWholeAddress;
private DataObject expectedAddressCSV;
private MapService mService;
private static Logger logger = Logger.getLogger(
AddressCleansingServiceTest.class );
protected void setUp() throws Exception {
expectedAddress = createAddress(
"IBM Corporation","1133 Westchester Avenue",
"","White Plains","NY","10604");
expectedWholeAddress = createWholeAddress(
"IBM Corporation","1133 Westchester Avenue",
"","White Plains","NY","10604");
expectedAddressCSV = createAddressCSV(expectedWholeAddress);
// Get the map service so we can invoke the mapping operation.
mService = (MapService) ServiceManager.INSTANCE.locateService(
"com/ibm/wbiserver/map/MapService");
}
protected void tearDown() throws Exception {
expectedAddress = null;
expectedAddressCSV = null;
expectedWholeAddress = null;
mService = null;
} |
清单 3 显示了以下内容:
- 由测试方法共享的私有数据成员的定义。这些数据成员将在 setUp() 中初始化,在 testXX() 中使用,并在 tearDown() 中销毁。
- 日志记录服务的创建,以便您能够在测试方法中记录日志。
- “实际”输入 SDO 的创建和初始化,以便您能够通过 createAddress() 方法将其传递给该映射。这只是创建了一个 Address SDO 并将其初始化为给定的值。(请参见项目交换文件以了解其实现。)
- “预期的”输出 SDO 的创建和初始化,以便您能够将其与该映射返回的实际输出做比较。这是通过 createWholeAddress() 和 createAddressCSV() 方法完成的。(请参见项目交换文件以了解其实现。)
-
创建测试方法
JUnit 命名约定规定所有测试方法名称都应以单词“test”开头。这些方法不带任何参数,是空方法。测试失败通过引发未经检查的异常来指示,通常是使用 JUnit 提供的断言和故障方法。测试成功通过测试方法的完成来指示。此示例的测试方法类似于清单 4。
清单 4
public void testAddress_To_AddressCSVMap()
throws WBIMapNotFoundException, WBIMapFailureException, WBIMapServiceException {
try {
logger.debug("Invoking Address_To_AddressCSV map.");
BOFactory bof = (BOFactory)ServiceManager.INSTANCE.locateService(
"com/ibm/websphere/bo/BOFactory");
DataObject actualAddressCSV = bof.create(
"http://L_AddressCleansingService", "AddressCSV");
HashMap inputMap = new HashMap();
HashMap outputMap = new HashMap();
inputMap.put("Address", expectedAddress);
outputMap.put("AddressCSV", actualAddressCSV);
mService.transform("http://L_AddressCleansingService",
"Address_To_AddressCSV", inputMap, outputMap, (ExecutionContext)null);
assertEquals(actualAddressCSV.getString("wholeAddress"),
expectedAddressCSV.getString("wholeAddress"));
} catch (WBIMapNotFoundException e) {
logger.debug("WBIMapNotFoundException: " + e.getMessage());
throw e;
} catch (WBIMapFailureException e) {
logger.debug("WBIMapFailureException: " + e.getMessage());
throw e;
} catch (WBIMapServiceException e) {
logger.debug("WBIMapServiceException: " + e.getMessage());
throw e;
}
} |
清单 4 显示了以下内容:
- 使用 Log4J 在测试过程中显示某些消息。请注意,Log4J.properties 文件需要在类路径上,以指定要使用的搜索路径,这里是通过向应用程序服务器的类路径添加文件夹来实现的。为此,请执行以下步骤:
- 打开管理控制台。
- 导航到 Application servers => server1 => Process Definition => Java Virtual Machine。
- 将您放置 log4j.properties 文件的文件夹添加到类路径,如清单 5 所示。
清单 5
log4j.rootLogger=WARN, RootAppender, ConsoleAppender
log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender.layout.ConversionPattern=[%d] %-5p %c{2} - %m%n
log4j.logger.com.ibm.issw=DEBUG |
- 使用 transform() 方法调用数据映射。此示例中使用了通用的 transform() 方法,它可以调用将一个或多个 SDO 转换为另一个 SDO 的映射,但是您也可以使用 simpleTransform() 方法调用数据映射,因为此方法从一个 SDO 转换为另一个 SDO。清单 6 中的代码片段显示了如何使用 simpleTransform()。
清单 6
mService.simpleTransform(
" http://L_AddressCleansingService”,
"Address_To_AddressCSV"
input,
output); |
- 有关该操作返回的数据的一连串断言;特别是,您将考虑映射的定义并包括有关每个转换的断言。为此,您将使用输入和输出数据对象上的 get 方法,并使用 JUnit assertEquals()。
有了此代码后,您就做好了运行测试的准备。
3. 运行测试用例
要运行测试,请执行以下操作:
-
首先,将测试模块添加到服务器,并确保服务器已启动。
-
在 Business Integration 透视图中,转到 Servers 视图。右键单击服务器,选择 Add Remove Projects,并将 T_AddressCleansingServiceApp 添加到服务器。您现在已经拥有了可用于执行的测试类。
-
要执行测试类,请转到 J2EE 透视图中的 Project Explorer 视图。选择 AddressCleansingServiceTest 类,然后从 Run 菜单中选择 Run...。
-
在 Run 对话框中,从可能的 Configurations 列表中选择 JUnit,然后单击 New。
-
选择 Arguments 窗格。在 VM 参数下,输入 -D 参数,如清单 7 所示。(此参数指定本地主机和端口 9083;如果您的服务器或用于 HTTP 请求的端口与此不同,请根据需要调整此字符串以匹配您的值。)
-Dcactus.contextURL=http://localhost:9083/T_AddressCleansingServiceJUnitWeb
|
-
选择 Run 来启动测试。JUnit 视图然后显示运行测试的结果(图 3)。
图 3. 执行测试的结果
现在您已经建立了这个启动配置,您只需选择它并单击 Run => JUnit Test 即可重复运行该类。
总结
本文演示了如何为数据映射编写测试用例,以及如何使用 JUnit 和 Cactus 在 WebSphere Process Server 容器中运行它们。这使您能够在实现使用 SDO 数据类型和数据映射的业务流程(SCA 模块)之前,首先为 SDO 数据类型和数据映射编写测试用例。这些测试的可用性提供了有关数据映射的快速反馈,并支持 SOA 解决方案中随后可能需要的数据类型重构。在第 2 部分中,您将看到如何在持续集成服务器中运行这些单元测试用例。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 代码样例 | TestingExample.zip | 972 KB | HTTP |
|---|
参考资料
关于作者  | |  |
Donald Vines 是 IBM 的一名执行 IT 架构师,他负责北美范围的 WebSphere 迁移实践。他目前从事的工作是为 IBM 主要客户创建解决方案体系结构,并在开发 SOA 和企业现代化项目过程中指导设计师和软件开发人员。他曾是对象管理组织 (Object Management Group, OMG) 的一位技术代表,在该组织中和其他人一同创立在 Internet 中广泛使用的 Internet Inter-ORB Protocol (IIOP)。Don 还是 Sun 认证的企业架构师、Sun 认证的 Java 程序员和 OMG 认证的 UML2 专业人员。 |
对本文的评价
|  |