`

全方位解析 Web Services 开发步骤

    博客分类:
  • java
阅读更多

基本开发环境

操作系统:本教程使用的为 Windows Vista Enterprise, 如果您的系统是 Linux 的,请选择下载对应版本的其他工具,包括开发工具、Java EE 服务器、Apache Ant、SoapUI。

开发工具:Eclipse IDE for SOA Developers 版本,请到 http://www.eclipse.org/downloads/网站下载,这个版本的 Eclipse 工具集成了一些 Web Services 插件,对于开发 Web Services 提供了一些便利。

Java EE 服务器:Apache-Tomcat-6.0.18,可以到 http://tomcat.apache.org/download-60.cgi下载,使用 5.0 以上的任何版本都可以的,当然,您也可以使用 Jboss 等其他 Java EE 服务器。

Jdk:到 http://java.sun.com 下载 1.5.0_17 版本,下载后安装即可。

其他工具:Apache Ant vsersion “1.6.5”用于代码打包,到 http://ant.apache.org/下载;SoapUI 3.5 用于 Web Services 的测试,到 http://www.soapui.org/下载,任何版本都可以,对于本教程没有影响。


Web Services 介绍

Web Services 是建立可交互操作的分布式应用程序的新平台 ; Web Services 平台是一套标准,它定义了应用程序如何在 Web 上进行交互操作 , 你可以用任何你喜欢的语言,在任何你喜欢的平台上写 Web Services, 只要我们可以通过 Web Services 标准对这些服务进行查询和访问。简单的说 Web Service 就是一些模块化的应用程序,这些应用程序能在 Web 上描述、发布、定位和调用。实现 Web Services 的方式也有很多种,本文也不一一介绍了,找几个我认为最常用的几种实现方式来与大家分享,首先介绍用 Axis 来实现 Web Services 的开发,然后介绍用 CXF 来开发 Web Services。对于每一种实现方式,我都以一种 step by step 的方式给大家用实例来讲解,从工程的建立一直到 Services 的交付使用,大家也可到网上搜索下这方面的相关教程,很多,但是大部分都是单单教你怎么来开发一个 Service,怎样来测试?怎样来验证是否可以交付给用户使用了?讲的很少,更不用说项目后期的自动化测试了,闲话少说,下面我们就进入 Service 的具体开发实例讲解,每一个实例都配以详细的分析过程。


用 Axis 开发 Web Services

准备环境

  1. Apache Axis2 1.5 build (30-04-2009) 到 http://ws.apache.org/axis2下载;
  2. 将 axis2.war 复制到 apache-tomcat-6.0.18 的 webapps 下;

axis2.war 这个包为我们提供了 Service 运行的基本环境,包括 Service 依赖的 jar 包,Service 的解析等,我们只需要将开发好的 Service 打包成 aar 包然后按照它的目录结构放进去就可以了,语言有时候是平白的,下面我们还是通过一个具体实例来讲解下。


开发 Services

新建一个 Java project, 命名为 ws_axis_example


图 1,新建 ws_axis_example
图 1,新建 ws_axis_example

然后新建一个 AxisService 类,我们下面就是将这个类发布成 Web Services,类的代码列表如清单 1 所示:


清单 1. AxisService 类

				
 package org.ibm.axis.service; 
 public class AxisService { 
	 public String sayHello(String EmpName){ 
		 return "Hello "+EmpName; 
	 } 
 } 

 

可以看到,这个AxisService 类就是一个普通的 Java Bean, 没有什么特殊的,就是这么简单。

接下来我们要新建一个 service.xml 文件,这个文件是最重要的,因为它定义了所有要发布出去的 service,文件内容如清单 2 所示:


清单 2. service.xml

				
 <service name="AxisService" scope="application"> 
    <description>AxisService</description> 
    <messageReceivers> 
        <messageReceiver 
 mep="http://www.w3.org/2004/08/wsdl/in-only" 
 class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/> 
 <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" 
 class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> 
    </messageReceivers> 
 <parametername="ServiceClass"> 
 org.ibm.axis.service.AxisService</parameter> 
 </service> 
然后再新建一个 build 文件,命名为 build.xml, 内容如清单 3 所示:



清单 3. build.xml

				
 <project name="service" basedir="." default="makeService"> 
	 <property name="dist.dir" value="dist" /> 
 <property name="dist.dir.classes" value="${dist.dir}/classes" /> 
 <property name="AXIS2_HOME" 
 value="E:\gdcc\tools\axis2-1.5-bin\axis2-1.5"/> 
	 <path id="build.class.path"> 
		 <fileset dir="${AXIS2_HOME}/lib"> 
			 <include name="*.jar" /> 
		 </fileset> 
	 </path> 
	 <target name="makeService" depends=""> 
 <copy file="src/services.xml" tofile="${dist.dir.classes}/META-INF/services.xml" 
			 overwrite="true" /> 
		 <javac srcdir="src" destdir="${dist.dir.classes}" 
			 includes="org/ibm/axis/service/*"> 
			 <classpath refid="build.class.path" /> 
		 </javac> 
 <jar basedir="${dist.dir.classes}" destfile="${dist.dir}/AxisService.aar" /> 
	 </target> 
 </project> 
熟悉 ant 的开发人员对于上面的脚本应该很容易看明白,这里就不详细解释了,主要功能就是根据 Axis 的标准打成 aar 包。
到目前为止 ws_axis_example 的目录结构如图 2 所示:



图 2. ws_axis_example 工程目录结构
图 2. ws_axis_example 工程目录结构

运行 ant 脚本, E:\gdcc\tools\apache-ant-1.6.5\bin\ant -f E:\ws_IBM\ws_axis_example\build.xml 注:ant 放在了 E:\gdcc\tools\apache-ant-1.6.5 目录下。执行结果如下:

 Buildfile: E:\ws_IBM\ws_axis_example\build.xml 

 makeService: 
     [copy] Copying 1 file to E:\ws_IBM\ws_axis_example\dist\classes\META-INF 
      [jar] Building jar: E:\ws_IBM\ws_axis_example\dist\AxisService.aar 

 BUILD SUCCESSFUL 
 Total time: 3 seconds 
 
 

然后我们将 AxisService.aar 压到axis2.war 的 WEB-INF\services 目录下,结果如图 3 所示:


图 3. 加入 AxisService.aar 后 axis2.war 的 services 包含的文件
图 3. 加入 AxisService.aar 后 axis2.war 的 services 包含的文件

接下来,启动 Tomcat,待启动完成后在浏览器中输入 http://localhost:8080/axis2/services/AxisService?wsdl,如果显示结构如清单 4 所示,则表示我们的 Service 发布成功了,否则按照以上步骤仔细检查下。


清单 4. AxisService 的 WSDL 内容片段

			<?xml version="1.0" encoding="UTF-8" ?> 
- <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
xmlns:ns1="http://org.apache.axis2/xsd" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
xmlns:ns="http://service.axis.ibm.org" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
targetNamespace="http://service.axis.ibm.org">
  <wsdl:documentation>AxisService</wsdl:documentation> 
- <wsdl:types>
- <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" 
targetNamespace="http://service.axis.ibm.org">
- <xs:element name="sayHello">
- <xs:complexType>
- <xs:sequence>
  	<xs:element minOccurs="0" name="args0" nillable="true" type="xs:string" /> 
  </xs:sequence>
  </xs:complexType>
  </xs:element>
- <xs:element name="sayHelloResponse">
- <xs:complexType>
- <xs:sequence>
  <xs:element minOccurs="0" name="return" nillable="true" type="xs:string" /> 
  </xs:sequence>
  </xs:complexType>
  </xs:element>
  </xs:schema>
</wsdl:types>
- <wsdl:message name="sayHelloRequest">
  <wsdl:part name="parameters" element="ns:sayHello" /> 
  </wsdl:message>
- <wsdl:message name="sayHelloResponse">
  <wsdl:part name="parameters" element="ns:sayHelloResponse" /> 
  </wsdl:message>
- <wsdl:portType name="AxisServicePortType">
- <wsdl:operation name="sayHello">
  <wsdl:input message="ns:sayHelloRequest" wsaw:Action="urn:sayHello" /> 
  <wsdl:output message="ns:sayHelloResponse" wsaw:Action="urn:sayHelloResponse" /> 
  </wsdl:operation>
  </wsdl:portType>

. . . . . . 
  </wsdl:definitions>

 

因为 WSDL 文件太长,我们只截取其中一部分内容,我们主要看一下 <wsdl:types>、sayHelloRequest 和 sayHelloResponse 的内容,从中我们可以知道这个 service 的 Namespace 是http://service.axis.ibm.org, 暴露的 operation 是sayHello,request 需要的是一个字符串参数,response 是一个字符串类型。下面我们来测试下这个 service 是否可用。


单元测试— Axis

现在比较流行 TDD 开发模式,虽然我们不是按照这个模式开发的,但是单元测试也应是必不可少的。Web Services 的单元测试究竟怎么来写呢?其实他和普通 bean 的单元测试没什么区别,下面我们就用 JUnit 来测试下上面的 service。

新建一个 Java Project, ws_client, 然后新建 AxisServiceTest 类,AxisServiceTest 代码如清单 5 所示:


清单 5 AxisServiceTest.java 代码

				
 package org.ibm.axis.service.client; 
 import javax.xml.namespace.QName; 
 import junit.framework.Assert; 
 import org.apache.axis2.AxisFault; 
 import org.apache.axis2.addressing.EndpointReference; 
 import org.apache.axis2.client.Options; 
 import org.apache.axis2.rpc.client.RPCServiceClient; 
 import org.junit.Test; 

 public class AxisServiceTest { 
 private static Object[] initAxisTest(QName testMethod, Object[] opArgs, 
			 Class[] returnTypes) throws AxisFault { 
 RPCServiceClient serviceClient = new RPCServiceClient(); 
     Options options = serviceClient.getOptions(); 
 EndpointReference targetEPR = new EndpointReference( 
 "http://localhost:8080/axis2/services/AxisService"); 
		 options.setTo(targetEPR); 
 Object[] response = serviceClient.invokeBlocking(testMethod, opArgs, 
				 returnTypes); 
		 return response; 
	 } 
 @Test 
 public void testSayHello() throws AxisFault { 
 Object[] opSayHelloArgs = new Object[] { "Mr Jack" }; 
		 Class[] returnTypes = new Class[] { String.class }; 
 QName opSayHello = new QName("http://service.axis.ibm.org", "sayHello"); 
 Object[] response = initAxisTest(opSayHello, opSayHelloArgs,returnTypes); 
     String result = (String) response[0]; 
     Assert.assertEquals("Hello Mr Jack", result); 
	 } 
 } 

 

对于 EndpointReference 和 QName 我们都可以从 WSDL 中得到,我们在上面也简单介绍了。输入参数是"Mr Jack",输出是 String 类型,期望结果与"Hello Mr Jack"相同,运行 JUnit. 结果如图 4 所示:令人兴奋的绿色长条,测试成功。


图 4. JUnit 运行结果
图 4. JUnit 运行结果

下面我们简单介绍下用 SoapUI 来测试 AxisService。 新建一个 soapUI Project,Project 名字为 WS_IBM, 在 Initial WSDL/WADL: 中输入 http://localhost:8080/axis2/services/AxisService?wsdl 完成后的界面如图 5 所示:


图 5. WS_IBM 工程结构
图 5. WS_IBM 工程结构

SOAP request 如清单 6 所示:


清单 6 . AxisService request

				
 <soap:Body> 
      <ser:sayHello> 
         <!--Optional:--> 
         <ser:args0>Mr Jack</ser:args0> 
      </ser:sayHello> 
   </soap:Body> 

点击运行后 SOAP response 如清单 7 所示:



清单 7 . AxisService response

				
 <soapenv:Body> 
      <ns:sayHelloResponse xmlns:ns="http://service.axis.ibm.org"> 
         <ns:return>Hello Mr Jack</ns:return> 
      </ns:sayHelloResponse> 
   </soapenv:Body> 

 

不知道您发现没有,我们在用 JUnit 测试和用 soapUI 测试时输入的参数值是一样的,得到的结果也完全一样,至此 AxisService 的开发与测试就完成了,是不是很简单?至于复杂的 Service 也都是按照这几步开发的,第一步,开发 Services;第二步,完成 service.xml 文件;第三步,发布 Service;关键的三步,但是我们也不能忘记最后一步,就是 Service 的测试,这是检查 Service 是否可用的最基本测试。以上的测试过程我们在讲自动化测试时,大部分都会用到的。上面我们提到 WSDL 文件,除了通过上面这个方式可以生成 WSDL 文件外,我们还可以通过命令行方式来生成 WSDL 文件,如下所示: E:\gdcc\tools\axis2-1.5-bin\axis2-1.5\bin\java2wsdl -cp . -cn org.ibm.axis.service.AxisService -o E:/ -of AxisService.wsdl 生成的 WSDL 文件放在了 E 盘下,名称为 AxisService.wsdl。下面我们在学习下用 CXF 怎样来开发 service 的。


用 CXF 开发 Web Services

新建一个 Java project 工程,命名为 ws_cxf_example, 创建 service 类,CXFService.java 和 CXFServiceImpl.java, 代码分别见清单 8 和清单 9 所示:


清单 8. CXFService.java

				
 package org.ibm.cxf.service; 

 public interface CXFService { 
 public String sayHello(String name); 

 } 



清单 9. CXFServiceImpl.java

				
 package org.ibm.cxf.service.impl; 

 import org.ibm.cxf.service.CXFService; 

 public class CXFServiceImpl implements CXFService{ 

	 public String sayHello(String name) { 
		 return "Hello "+name; 
	 } 
 } 

 

接下来,我们要新建一个 cxf-servlet.xml 和 web.xml 文件,文件内容分别如清单 10 和清单 11 所示:


清单 10. cxf-servlet.xml

				
 <?xml version="1.0" encoding="UTF-8"?> 
 <beans xmlns="http://www.springframework.org/schema/beans"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	 xmlns:simple="http://cxf.apache.org/simple"
 xmlns:soap="http://cxf.apache.org/bindings/soap"
	 xsi:schemaLocation="
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd 
 http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd"> 

	 <simple:server id="CXFservice" serviceClass="org.ibm.cxf.service.CXFService"
		 address="/CXFService"> 
		 <simple:serviceBean> 
 <bean class="org.ibm.cxf.service.impl.CXFServiceImpl" /> 
		 </simple:serviceBean> 
	 </simple:server> 
 </beans> 



清单 11. web.xml

				
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//
 DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> 
 <web-app> 
 <display-name>cxf</display-name> 
	 <description>cxf</description> 
	 <servlet> 
		 <servlet-name>cxf</servlet-name> 
		 <display-name>cxf</display-name> 
		 <description>Apache CXF Endpoint</description> 
		 <servlet-class>org.apache.cxf.transport.servlet.CXFServlet
		 </servlet-class> 
		 <load-on-startup>1</load-on-startup> 
	 </servlet> 
	 <servlet-mapping> 
		 <servlet-name>cxf</servlet-name> 
		 <url-pattern>/services/*</url-pattern> 
	 </servlet-mapping> 
	 <session-config> 
		 <session-timeout>30</session-timeout> 
	 </session-config> 
 </web-app> 

 

最后我们还是需要新建一个 ant 脚本来打包,build.xml,其脚本如清单 12 所示:


清单 12. build.xml for CXFService

				
 <project name="service" basedir="." default="war"> 
	 <property name="dist.dir" value="${basedir}/WEB-INF" /> 
	 <property name="dist.dir.classes" value="${dist.dir}/classes" /> 
 <path id="build.class.path"> 
		 <fileset dir="${basedir}/lib"> 
			 <include name="*.jar" /> 
		 </fileset> 
	 </path> 
	 <target name="war" depends=""> 
		 <javac srcdir="src" destdir="${dist.dir.classes}" 
 includes="org/ibm/cxf/service/*/*"> 
			 <classpath refid="build.class.path" /> 
		 </javac> 
		 <war destfile="${dist.dir}/cxf.war" webxml="${dist.dir}/web.xml"> 
			 <classes dir="${dist.dir.classes}" /> 
			 <lib dir="${basedir}/lib" /> 
			 <webinf dir="${dist.dir}"> 
				 <include name="cxf-servlet.xml" /> 
			 </webinf> 
 </war> 
	 </target> 
 </project> 

 

运行 ant 脚本,将生成的 cxf.war 包放到 tomcat 的部署目录下,启动 tomcat,待启动完成后,我们在浏览器中输入 http://localhost:8080/cxf/services/CXFService?wsdl 将显示如下信息:

				<?xml version="1.0" encoding="UTF-8" ?> 
- <wsdl:definitions name="CXFService" targetNamespace="http://service.cxf.ibm.org/"
 xmlns:ns1="http://schemas.xmlsoap.org/wsdl/soap/http"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="http://service.cxf.ibm.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <wsdl:types>
- <xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 
targetNamespace="http://service.cxf.ibm.org/" xmlns:tns="http://service.cxf.ibm.org/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="sayHello" type="tns:sayHello" /> 
……
  </wsdl:definitions>

 

 </wsdl:definitions>

出现如上信息表示 service 发布成功了,关于 service 的详细信息在这个 WSDL 文件中都有定义,如出现问题请仔细检查以上步骤。

下面我们测试下 service 是否可用。


单元测试—— CXF

新建一个 JUnit 测试类 CXFServiceTest,代码如清单 13 所示:


清单 13. CXFServiceTest.java

				
 package org.ibm.axis.service.client; 
 import junit.framework.Assert; 
 import org.apache.cxf.frontend.ClientProxyFactoryBean; 
 import org.ibm.cxf.service.CXFService; 
 import org.junit.Test; 
 public class CXFServiceTest { 
	 @Test 
	 public void testSayHello(){ 
		 ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); 
		 factory.setServiceClass(CXFService.class); 
		 factory.setAddress("http://localhost:8080/cxf/services/CXFService"); 
		 CXFService client = (CXFService) factory.create(); 
		 String response = client.sayHello("jack"); 
		 Assert.assertEquals("Hello jack", response); 
	 } 
 } 

 

其中 Address 可以从上面的 WSDL 文件中得到。

运行 JUnit test, 结果如图 6 所示:


图 7. Junit cxf service 测试结果
图 7. Junit cxf service 测试结果

SoapUI 的测试和 Axis 的是一样的。右击 WS_IBM 选择 Add WSDL,在 WSDL Location 输入框中输入 http://localhost:8080/cxf/services/CXFService?wsdl 输入参数 jack, 点击运行,如果看到 response 信息是 Hello jack, 恭喜你,成功了。


清单 14. CXFService request

				
 <soapenv:Body> 
      <ser:sayHello> 
         <!--Optional:--> 
         <ser:arg0>jack</ser:arg0> 
      </ser:sayHello> 
   </soapenv:Body> 

 

清单 14. CXFService response

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
   <soap:Body> 
      <ns1:sayHelloResponse xmlns:ns1="http://service.cxf.ibm.org/"> 
         <return xmlns="http://service.cxf.ibm.org/">Hello jack</return> 
      </ns1:sayHelloResponse> 
   </soap:Body> 
 </soap:Envelope> 

 


使用 spring 框架来集成 Web Services 开发

Sping 框架是当今比较流行的,讲 Web Services 不能不提一下它,那么 Web Services 又是怎样与 Spring 框架集成开发的呢?下面我们通过一个例子来具体讲解下。

新建 ws_cxf_with_spring 工程 , 然后新建 service 类 SpringService.java 和SpringServiceImpl.java, 一个是接口类,一个是实现类,类代码详见清单 15 和清单 16.


清单 15. SpringService.java 代码

				
 package org.ibm.spring.service; 

 import javax.jws.WebService; 
 @WebService 
 public interface SpringService { 
    String sayHello(String name); 
 } 



清单 16. SpringServiceImpl.java 代码

				
 package org.ibm.spring.service.impl; 

 import javax.jws.WebService; 

 import org.ibm.spring.service.SpringService; 

 @WebService(endpointInterface = "org.ibm.spring.service.SpringService") 
 public class SpringServiceImpl implements SpringService { 

    public String sayHello(String name) { 
        return "Hello " + name; 
    } 
 } 

 

注意,这里我们使用了 annotation 来开发 Web Services 而不是通过在 cxf-servlet.xml 增加 service 的定义来实现的。两种实现方式各有利弊,选择自己熟悉的,感觉舒服的就可以了。 接下来就是编写两个我们比较熟悉的文件 beans.xml 和 web.xml, 代码见清单 17 和清单 18.


清单 17. beans.xml

				
 <?xml version="1.0" encoding="UTF-8"?> 
	 <!-- START SNIPPET: beans --> 
 <beans xmlns="http://www.springframework.org/schema/beans"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	 xmlns:jaxws="http://cxf.apache.org/jaxws"
	 xsi:schemaLocation="
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> 
	 <import resource="classpath:META-INF/cxf/cxf.xml" /> 
	 <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> 
	 <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 
	 <jaxws:endpoint id="springService"
		 implementor="org.ibm.spring.service.impl.SpringServiceImpl" 
		 address="/SpringService" /> 
 </beans> 

 

这个 beans.xml 文件是 spring 必须的,注意其中的 address="/SpringService",我们就是通过这个地址访问 service 的,通过 implementor 指定具体的实现 Bean, 是不是很简单。


清单 18. web.xml

				
 <?xml version="1.0" encoding="ISO-8859-1"?> 
 <!DOCTYPE web-app 
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd"> 
 <web-app> 
	 <context-param> 
		 <param-name>contextConfigLocation</param-name> 
		 <param-value>WEB-INF/beans.xml</param-value> 
	 </context-param> 
	 <listener> 
		 <listener-class> 
			 org.springframework.web.context.ContextLoaderListener 
		 </listener-class> 
	 </listener> 
	 <servlet> 
		 <servlet-name>CXFServlet</servlet-name> 
		 <display-name>CXF Servlet</display-name> 
		 <servlet-class> 
			 org.apache.cxf.transport.servlet.CXFServlet 
		 </servlet-class> 
		 <load-on-startup>1</load-on-startup> 
	 </servlet> 
	 <servlet-mapping> 
		 <servlet-name>CXFServlet</servlet-name> 
		 <url-pattern>/*</url-pattern> 
	 </servlet-mapping> 
 </web-app> 

 

最后编写一个 build.xml 文件,用于打包,脚本见清单 19.


清单 19. build.xml

				
 <project name="service" basedir="." default="war"> 
	 <property name="dist.dir" value="${basedir}/WEB-INF" /> 
	 <property name="dist.dir.classes" value="${dist.dir}/classes" /> 
	 <path id="build.class.path"> 
		 <fileset dir="${basedir}/lib"> 
			 <include name="*.jar" /> 
		 </fileset> 
	 </path> 
	 <target name="war" depends=""> 
		 <javac srcdir="src" destdir="${dist.dir.classes}" 
			 includes="org/ibm/spring/service/*/*"> 
			 <classpath refid="build.class.path" /> 
		 </javac> 
		 <war destfile="${dist.dir}/cxfWithSpring.war" 
			 webxml="${dist.dir}/web.xml"> 
			 <classes dir="${dist.dir.classes}" /> 
			 <lib dir="${basedir}/lib" /> 
			 <webinf dir="${dist.dir}"> 
				 <include name="beans.xml" /> 
			 </webinf> 
		 </war> 
	 </target> 
 </project> 

 

运行 ant 脚本,然后将 cxfWithSpring.war 放到 Tomcat 的部署目录下,运行 Tomcat, 待 server 启动完成后,输入 http://localhost:8080/cxfWithSpring/SpringService?wsdl,将会看到 WSDL 文件 , 这里就不列出来了。


单元测试 -SpringService

这里我们只用 SoapUI 来看下,发布的 service 是否可以正常访问,是否可以得到期望的结果,至于开发客户端的单元测试请读者自行按照上面的代码来完成。

将 http://localhost:8080/cxfWithSpring/SpringService?wsdl 加入到 WS_IBM 这个 soapUI 工程,然后在 request 的参数处输入 Jack, 如果 response 是 Hello Jack, 表示 SpringService 一切正常,可以使用了。


清单 20. SpringService request

				
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:ser="http://service.spring.ibm.org/"> 
   <soapenv:Header/> 
   <soapenv:Body> 
      <ser:sayHello> 
         <arg0>Jack</arg0> 
      </ser:sayHello> 
   </soapenv:Body> 
 </soapenv:Envelope> 



清单 21. SpringService response

				
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
   <soap:Body> 
      <ns2:sayHelloResponse xmlns:ns2="http://service.spring.ibm.org/"> 
         <return>Hello Jack</return> 
      </ns2:sayHelloResponse> 
   </soap:Body> 
 </soap:Envelope> 

 

现在有这么个场景,假如我们开发完了几十个 services,然后要交给 QA Team 来进行测试,大家应该很熟悉一个项目的测试过程吧,alpha 之前就要出好几个 build 的,然后还要 beta,最后才 GA,每一阶段要出的 build 都不少的,为了保证 build 的质量,每次出 build 前,基本都要求开发人员将 service 先测试下,然后才能提交给 QA 进行系统测试,我想这时候开发人员一定会有一种抱怨,我的 service 也没有修改呀,怎么也要测试呀?每次都要重复的做这种没有什么意义的工作,其实这个工作是有意义的,你没有修改,也许其他人修改了,说不定你的代码和其他人修改的代码间有一定关联的,所以说测试还是必要的,这里面值得考虑的是,是不是每一次都需要开发人员手工那样一个一个 service 来测试呢?当然不用的,下面我就同大家来分享下 web Services 的自动化测试方法。


Web Services 自动化测试

Web Services 要实现自动化测试我们要依赖 SoapUI 这个强大的工具,还记得我们建的 Soap

Project WS_IBM 吧,在完成上面的测试后,WS_IBM 的目录结构如图 6 所示:


图 7. WS_IBM 项目结构
图 7. WS_IBM 项目结构

接下来,在 WS_IBM 工程上右击,选择 New TestSuite, 在 Specify name of TestSuite 下输入 WebService_TestSuite,然后再 WebService_TestSuite 上右击,选择 New TestCase, 输入 Axis_sayHello, 然后再 Axis_sayHello 上右击,选择 Add Step, 然后选择 Test Request, 输入 sayHello, 随后会弹出一个界面供你选择,如图 6 所示:我们选择 AxisServiceSoap12Binding->sayHello


图 8. 选择 request
图 8. 选择 request

我们按照上面的步骤将 CXFServiceSoapBinding->sayHellot 添加到 WebService_TestSuite,Test Case 名称为 CXF_sayHello。

接下来我们编写一个 ant 脚本名称为 build_ws.xml, 脚本内容如清单 22 所示:

清单 22. build_ws.xml

 <?xml version="1.0"?> 
 <!-- *************************************************************** --> 
 <!-- Ant build script for web Services --> 
 <!-- *************************************************************** --> 
 <project name="smartdm" default="ws-test" basedir="."> 
	 <property file="build.properties"/> 
	 <target name="ws-test"> 		
	  <exec dir="${soapui.dir}\\bin" executable="cmd.exe" > 
	 <arg line="/c testrunner.bat -j -f${junit.reports} ${soapui.project.file} "
	 /> 
	 </exec> 
	  	
  <!-- Generate the JUnit reports --> 
   <junitreport todir="${junit.reports}"> 
	    <fileset dir="${junit.reports}" includes="TEST-*.xml"/> 
	     <report todir="${junit.reports}" format="frames"/> 
    </junitreport> 
	 </target> 
 </project> 
 Ant 脚本用到的 properties 文件 build.properties 内容如清单 23 所示:

 

清单 23. build.properties

 soapui.dir=E:/tools/soapUI-3.5 
 soapui.project.file=E:/ws_soapUI/WS-IBM-soapui-project.xml 
 junit.reports=E:/ws_soapUI/reports 

 

ok,大功告成了,以上三个 service 的测试,我们就可以用 build_ws.xml 这个文件来完成了,每次只需要简单的一行命令,是不是很简单,再也不用一个一个 service 点了,各位有没有什么感慨,这只是三个 service,如果 service 数量大的话,你会更加爱上这种方法的。感慨的同时我想一定还伴随着一些疑惑,文章开始我们说是自动化测试,而现在还是需要一行命令,名不符实呀。其实我已经将 xml 脚本告诉大家了,只需要大家来调用这个脚本就可以了,至于调用方式,你可以用一行命令,也可以通过一些软件来自动调用,比如通过 Hudson 等,我们可以在这些软件中设置一些场景,如有代码变动,就自动调用 build_ws.xml 文件。Hudson 是一种 CI 服务器,这种 CI 服务器的工作过程如下所示:首先开发者检查新增和修改到源代码仓库后的代码。然后 CI 服务器会为每一个项目创建了一个单独的工作区。当预设或请求一次新的构建时,它将把源代码仓库的源码存放到对应的工作区,哪里构建就执行哪里。接着 CI 服务器会在新近创建或者更新的工作区内执行构建过程。然后一旦构建完成,CI 服务器就会在一个新的构件中选择性地执行原先定义的一套测试。如果构建失败,相关责任人将会通过电子邮件、即时短信或者其他的方式获取到 ( 失败 ) 通知。如果构建成功,这个构件会被打包并转移到一个部署目标 ( 如应用服务器 ) 上。最后 CI 服务器通常会用某种控制台来进行项目的和调试,并且根据请求发起相应的操作,诸如即时构建、生成报告,或者检索一些构建好的构件。

 

参考资料

学习

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics