首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

怎么简单模拟Web服务

2012-09-02 
如何简单模拟Web服务在SOA环境中,系统不可避免地要与其他系统进行交互,可以是基于SOAP的Web服务,基于RESTf

如何简单模拟Web服务

在SOA环境中,系统不可避免地要与其他系统进行交互,可以是基于SOAP的Web服务,基于RESTful Web服务,基于消息队列,甚至是基于RPC远程调用。随着系统依赖的增长,对单个系统进行测试也变得越来越困难,如何有效地隔离各个系统,对系统进行单独的测试呢?

?

本文会给大家介绍一个简单的测试方法——基于Mock进行测试

?

开发过程中常用的测试有单元测试与集成测试,下面也分成两部分来做说明。

package mock.sample;/** * 用作范例的接口 */public interface SampleService { String operate(String str);}?

项目代码Operator类中引用了该服务,需要取得返回值进行后续操作。

package mock.sample;/** * SampleService的调用类  */public class Operator {    private SampleService sampleService;    /**     * 调用sampleService     * 1、如果返回值result长度小于等于5,返回str+result     * 2、如果返回值result长度大于5,返回result      */    public String operate(String str) {        String result = sampleService.operate(str);        if (result != null && result.length() <= 5) {            result = str + result;        }        return result;    }    public void setSampleService(SampleService sampleService) {        this.sampleService = sampleService;    }}
?

在编写单元测试时,为SampleService模拟一个对象注入Operator。关于jMock的使用,请参考jMock的《Getting Started》或者《Cheat Sheet》。jMock主要是使用录制-回放的方式,通过预先设定期望的输入与输出实现Mock。

?

package mock.sample;import static org.junit.Assert.assertEquals;import org.jmock.Expectations;import org.jmock.Mockery;import org.jmock.integration.junit4.JMock;import org.jmock.integration.junit4.JUnit4Mockery;import org.junit.Test;import org.junit.runner.RunWith;@RunWith(JMock.class)public class OperatorTest {    private Mockery context = new JUnit4Mockery();    @Test    public void testOperate() {        Operator operator = new Operator();        final SampleService sampleService = context.mock(SampleService.class);        operator.setSampleService(sampleService);        context.checking(new Expectations() {            {                oneOf(sampleService).operate("hi");                will(returnValue("HelloWorld!"));                oneOf(sampleService).operate("hello");                will(returnValue("world"));            }        });        assertEquals("HelloWorld!", operator.operate("hi"));        assertEquals("helloworld", operator.operate("hello"));    }}
?

单元测试中直接通过编码的途径用jMock模拟了外部系统的逻辑,业务代码并不关注究竟是调用了真是的Web服务,还是Mock对象。同样的,对于DAO等依赖也可以使用同样的方式进行模拟。

?

二、集成测试中的Mock

?

集成测试时同样可以通过编程的方式实现Mock,比如在Spring上下文中加载Mock的Bean而非通过XFire(或其他Web服务框架)引入的客户端。但这种做法未免过于繁琐,而且在希望改变Mock类返回结果时,可能需要修改代码重新编译发布。更有甚者,上线时如果忘记从测试的配置换回生产配置,就会出大问题。

?

当然,你可以选择部署一台真实的服务提供方,但有时出于种种原因,这并不是一个很好的选择。

?

相信在测试Web服务时,不少人都是用过soapUI,但仅限于使用soapUI调用Web服务,其实强大的soapUI还可以Mock服务,根据事先的配置(Groovy脚本、XPath匹配、顺序、随机等方法)返回不同的结果。其实现原理简单地说就是根据给定的WSDL模拟Web服务,接受请求后根据配置解析请求,随后返回预先设定的结果,这里的请求和响应都是标准的SOAP报文。

?

简单实现步骤如下:

    创建一个新的soapUI项目,在“New soapUI Project”对话框中输入WSDL地址,随后选中“Create MockService”。在“Generate MockService”对话框中选中要模拟的操作,Path和Port尽量和真实的目标服务器保持一致。例如,发布WSDL的路径可能是http://xxx:8080/services/sampleService?wsdl,那么Path就是/services/cardInfoService,Port为8080。编辑应答SOAP报文及返回逻辑。

在MockService的各个方法上点右键可以进入MockOperation Editor或者直接创建新的MockResponse。MockService创建时,每个操作都会有个Response,没有设定规则时,这就是默认应答。

?

可以仅使用一个Response,多次调用需要不同结果时手工修改,但这样一点都不“自动化”,可以通过soapUI的分派机制自动根据规则返回对应结果。

?

soapUI支持的分派机制(详见MockOperations and Responses)有:

SCRIPT,使用Groovy脚本。SEQUENCE,按照MockResponse添加的顺序逐个返回。QUERY-MATCH,基于请求内容选择合适的结果返回。可以指定XPath路径及该节点的期望值,如果匹配的话返回对应Response。XPATH,与QUERY-MATCH类似,XPath节点的值就是要返回的MockResponse的名字。RAMDOM,随机返回。

个人认为XPATH和QUERY-MATCH这两种分派机制在复杂情况下比较好用,如果再复杂,可以考虑SCRIPT。以XPATH为例,假设请求报文如下:

?

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fac="http://sample.mock.SampleService">   <soapenv:Header/>   <soapenv:Body>      <fac:operate>         <fac:in0>hi</fac:in0>      </fac:operate>   </soapenv:Body></soapenv:Envelope>

?

可以设置两个MockResponse,名字分别为“hi”和“hello”,在编辑器中选择“XPATH” ,设置如下XPATH:

declare namespace fac='http://sample.mock.SampleService'//fac:in0

当//fac:in0的值是“hi”时就会返回名为“hi”的MockResponse。“hi”MockResponse内容:

?

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fac="http://sample.mock.SampleService">   <soapenv:Header/>   <soapenv:Body>      <fac:operate>         <fac:out>HelloWorld!</fac:out>      </fac:operate>   </soapenv:Body></soapenv:Envelope>
?

如果使用QUERY_MATCH,除了填写XPath,还要再填写“Expacted Value”,比如“hi”或者“hello”,然后“Dispatch to”中选择合适的MockResponse。

?

在项目中只需要把Web服务的Endpoint地址做成可配置的,就可以方便地调整测试与生产环境的Endpoint,实现Mock与真实服务器的切换。

?

使用Mock可以大大降低测试的成本,工欲善其事必先利其器,选择一个合适的Mock工具,可以帮助你更好的进行测试。So,行动吧~

?

?

?

热点排行