转载:http://blog.csdn.net/ronghuanye/article/details/71124127

1        简介

Dubbo目前的应用已经越来越广泛、或者基于Dubbo二次开发的也越来越多,使用到Dubbo的系统基本也是采用微服务架构设计的系统,多个系统、多个应用之间的接口是有依赖关系的,所以就会出现需要MOCK的应用场景。

当我们发布了两个应用A和B,应用A引用应用B发布的接口,那么我们的应用场景是MOCK应用B(接口提供方)。通常的MOCK方式是,测试人员自己发布一个一样的接口(应用C),然后把应用A的调用指向(应用C),这种方式可以解决MOCK,但是这种方式的弊端:

1.需要开发MOCK代码

2.对人员要求技能高

3.需要接口提供方的依赖jar

4.需要容器发布应用C

5.接口变更需要更新MOCK代码

6.发布时间长,需要编码发布


我们可以采取另外一个方式,通过添加dubbo的filter过滤器,通过过滤器拦截请求,把请求导向mock平台,或者拦截请求后直接返回已经缓存的响应数据,达到mock的效果而且可以配置返回的数据内容和响应时间。filter是放在消费端的(应用A),配置filter之后应用A的请求首先会到filter里面。

下面是添加filter后需要实现的工作流程图:

具体的filter代码实现请看下面的章节介绍!

RPC接口mock平台架构图:

2        RPC接口mock平台在接口测试中的用处

2.1             屏蔽关联接口依赖关系,快速定位接口的性能瓶颈点

当被测试接口依赖多个其他接口时,出现了性能问题后无法定位性能瓶颈是出在被测接口还是其他依赖的接口,这时可以使用接口mock平台屏蔽掉其他依赖的接口,这样就可以很快的定位是被测接口存在性能问题,还是其他依赖接口存在性能问题。

2.2             用mock平台代替依赖服务的部署,提高环境部署的效率,减少环境部署的工作量。

当进行集群测试时,需要部署大量的其他依赖服务器,如果依赖的服务部署比较繁琐,工作量较大时,可以考虑使用mock平台代替依赖服务的部署,既节省服务器资源又可提高部署环境的效率。

2.3             使用mock平台,可以方便查看被测试接口的依赖关系

从mock平台配置界面或者数据库可以看到被测接口依赖的其他接口列表:

2.4             使用mock平台的配置界面可以方便配置接口的mock参数(返回数据,mock开关,响应时间)

可以在mock平台的前端配置界面配置接口的mock参数,例如返回数据,mock开关,响应时间等。

3        RPC接口mock测试平台使用方法

3.1             实现com.alibaba.dubbo.rpc.Filter接口

实现com.alibaba.dubbo.rpc.Filter接口的类CustomConsumerFilter 代码如下:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import net.sf.json.JSONObject;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

@SuppressWarnings("deprecation")
public class CustomConsumerFilter implements Filter {
public static Map<String, Object> map = new HashMap<String, Object>(); //保存接口对象
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    Result result = null; 
 //定义一个返回对象;
    String interfaceName = invoker.getUrl().getPath();    //获取接口服务名称
String methodName = invocation.getMethodName();  //获取接口方法名称
Object[] arguments =invocation.getArguments();        //获取参数集合
List<String> paramTypes = new ArrayList<String>();
 //获取参数类型
for(int i=0; i<arguments.length; i++)
{
paramTypes.add(arguments[i].getClass().getTypeName());
}

Method method = null;

try {
method = Class.forName(interfaceName)
.getDeclaredMethod(methodName, invocation.getParameterTypes());
//获取调用方法
} catch (Exception e) {
e.printStackTrace();
}
Type returnType = method.getGenericReturnType();
 //获取返回类型
JSONObject responeJSON = new JSONObject();
if(map.containsKey(interfaceName + "+" + methodName + "+" + paramTypes.toString()))
{
responeJSON = (JSONObject) map.get(interfaceName + "+" + methodName + "+" + paramTypes.toString());

if(Integer.parseInt(responeJSON.getString("status"))==1)
{
String returnStr = responeJSON.getString("returnJson");
      Object returnJson = null;
//定义响应对象
      try {
      returnJson = JSON.parseObject(returnStr,Class.forName(returnType.getTypeName()));
} catch (Exception e) {
e.printStackTrace();
}
      
      result = new RpcResult();
//定义返回结果
      ((RpcResult) result).setResult(returnJson);
      ((RpcResult) result).setException(null);
}
else {
result = invoker.invoke(invocation);   //调用真实接口
}
}
else {
String url = "http://mock.vmall.com/tcep/";
//mock服务器地址
JSONObject jsonObj = new JSONObject();
String paramJson =JSON.toJSONString(arguments, SerializerFeature.WriteClassName);
//序列化入参为JSON串
      //请求测试平台查询接口mock信息
      jsonObj.put("interfaceName", interfaceName);
      jsonObj.put("methodName", methodName);
      jsonObj.put("paramTypes", paramTypes.toString());
      jsonObj.put("paramJson", paramJson);
      jsonObj.put("returnType", returnType.getTypeName());
      
      String resp = httpPost(url + "mock!goMock.action", jsonObj.toString());
responeJSON = JSONObject.fromObject(resp);
if(responeJSON.getBoolean("success"))
{
String mess = responeJSON.getString("message");
if(!mess.equals(""))
{
JSONObject responeJSON2 = JSONObject.fromObject(mess);
map.put(interfaceName + "+" + methodName + "+" + paramTypes.toString(), responeJSON2);
if(Integer.parseInt(responeJSON2.getString("status"))==1)
{
String returnStr = responeJSON2.getString("returnJson");
      Object returnJson = null;
//定义响应对象
      try {
      returnJson = JSON.parseObject(returnStr,Class.forName(returnType.getTypeName()));
} catch (Exception e) {
e.printStackTrace();
}
      
      result = new RpcResult();
//定义返回结果
      ((RpcResult) result).setResult(returnJson);
      ((RpcResult) result).setException(null);
}
else {
result = invoker.invoke(invocation);   //调用真实接口
}
} else {
result = invoker.invoke(invocation);   //调用真实接口
//然后把接口信息存到测试平台
jsonObj.put("returnJson", JSON.toJSONString(result.getResult()));
httpPost(url + "mock!addMock.action", jsonObj.toString());
}
}
}
        return result;
}
    /*  
  * 发送Http post请求
*/
    @SuppressWarnings("finally")
public String httpPost(String url,String jsonParam){
    DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
HttpResponse response = null;
String respStr = "";
try {
StringEntity entity = new StringEntity(jsonParam,"utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
post.setEntity(entity);
response = client.execute(post);
//获取响应数据
InputStreamReader reader = new InputStreamReader(response.getEntity().getContent(),"UTF-8");
BufferedReader br = new BufferedReader(reader);
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine())!=null){
sb.append(line);
}
respStr = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
finally {
client.close();
return respStr;
}
    }
}

Filter类的java工程如下:

注意:需要在工程中创建目录META-INF/dubbo,然后在目录中创建文件com.alibaba.dubbo.rpc.Filter,文件内容添加

CustomConsumerFilter=com.huawei.vmall.mock.CustomConsumerFilter

将上面的java类打成jar包

导出的jar包如下所示:

3.2             Cosumer端添加filter过滤器,加入依赖包,配置hosts映射地址

1、添加filter过滤器

在被测系统中找到dubbo配置文件,tomcat部署的应用一般是

webapps/ROOT/WEB-INF/classes/spring目录中的dubbo-context.xml

Jar包启动的应用一般是lib/conf/spring目录中的dubbo-context.xml

找到consumer配置,在filter中添加CustomConsumerFilter参数:

2、加入依赖包

filter类需要依赖的jar包如下:

在被测系统的lib目录中添加filter类依赖的jar和上一步导出的filter类jar包,filter类依赖的前面4个jar包一般都会已经存在lib目录中了,不需要再重新添加,后面3个jar如果已经存在则不需要添加,不存在则添加。

Tomcat方式启动的应用lib目录

Jar包方式启动的应用lib目录

注意:添加jar前先检查是否已经存在,版本不同也没有关系,如果已经存在则不需添加。

3、配置hosts映射地址

在被测系统服务器中添加hosts配置

其中10.41.150.52是mock服务器的ip地址,mock.vmall.com是mock服务器的域名,域名已经写死在filter类中不能改,ip地址可以根据实际部署ip进行修改。

3.3             调试被测接口,添加接口mock

添加完成filter和jar包后需要重新启动被测系统,然后在eclipse中调试RPC接口,调试成功后会在mock数据库中添加依赖的接口信息。

Mock数据库插入的数据,其中status为0表示没有开启mock,需要手工在界面或者数据库中改1才能开启mock;要保证接口返回数据的正确性,可以在界面或者数据库中修改returnJson字段修改返回数据。

3.4             验证接口mock是否正常

当开启了接口mock之后,在jmeter中执行接口测试场景,验证接口mock是否正常,需要查看jmeter是否报错,被测系统的日志是否报错,查看接口调用日志中调用依赖接口的响应时间是否为0或者为预定的值。

4      常见问题

1、调用RPC接口时日志报下面的错误

解决办法:

由于缺少以下相关依赖包

dubbo-2.5.3.jar,fastjson-1.1.15.jar,httpclient-4.5.2.jar,httpcore-4.4.4.jar,json-lib-2.4-jdk15.jar,ezmorph-1.0.6.jar,commons-collections-3.2.1.jar,将依赖包加入被测试系统的lib目录下就可以了(先检查一下lib目录下面是否已经存在相关jar包,版本不同也没有关系,如果已经存在则不需添加)

RPC接口mock测试的更多相关文章

  1. rpc接口mock平台

    转载:http://blog.csdn.net/ronghuanye/article/details/71124320 1.简介 平台采用struts.spring.mybatis框架开发设计,主要用 ...

  2. 接口Mock测试

    什么是Mock测试? Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取的比较复杂的对象(如 JDB ...

  3. 《如何进行接口mock测试》

    前言: Mock通常是指:在测试一个对象时,我们构造一些假的对象来模拟与其交互.而这些Mock对象的行为是我们事先设定且符合预期.通过这些Mock对象来测试对象在正常逻辑,异常逻辑或压力情况下工作是否 ...

  4. 利用eolinker实现api接口mock测试(mock server)

    转载:http://blog.csdn.net/naicha_qin/article/details/78276172 前后端分离或者是进行单元测试的时候,必须要用mock api替换掉第三方调用或者 ...

  5. Mock测试接口

    Mock使用场景: (1)创建所需的DB数据可能需要很长时间,如:调用别的接口,模拟很多数据,确保发布版本接口可用 (2)调用第三方API接口,测试很慢, (3)编写满足所有外部依赖的测试可能很复杂, ...

  6. Mock测试你的Spring MVC接口

    1. 前言 在Java开发中接触的开发者大多数不太注重对接口的测试,结果在联调对接中出现各种问题.也有的使用Postman等工具进行测试,虽然在使用上没有什么问题,如果接口增加了权限测试起来就比较恶心 ...

  7. mock测试框架Mockito

    无论是敏捷开发.持续交付,还是测试驱动开发(TDD)都把单元测试作为实现的基石.随着这些先进的编程开发模式日益深入人心,单元测试如今显得越来越重要了.在敏捷开发.持续交付中要求单元测试一定要快(不能访 ...

  8. Spring MVC如何测试Controller(使用springmvc mock测试)

    在springmvc中一般的测试用例都是测试service层,今天我来演示下如何使用springmvc mock直接测试controller层代码. 1.什么是mock测试? mock测试就是在测试过 ...

  9. 使用mockserver来进行http接口mock

    转载自:https://blog.csdn.net/heymysweetheart/article/details/52227379:(注,这个不是很符合我的要求,它主要的作用是可以通过简单的代码就能 ...

随机推荐

  1. Download RPM packages from a YUM repo without installing

    This how-to will explain how to download rpm packages from a yum repository without installing them. ...

  2. 2018超详细sublime text3+python3.x安装配置教程(附常用插件安装教程)

    导读 本文是关于2018年7月最新版sublime text3+pythin3.x下载及安装配置教程,sublime text3版本为3176,python版本为3.7,安装环境是基于windows1 ...

  3. hdu 4359 dp

    /* 题目大意:给n个节点的二叉树第i个节点的权值为2^(i-1), 求所有含左右子树的节点都符合左子树的权和小于右子树权和的种数. */ #include <iostream> #inc ...

  4. HDU2041 简单DP+规律

    超级楼梯 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. linxu安装方式

    安装Linux操作系统的5种方法以及心得这几天没有调别的东西,想起自己还不太会在没有安装光盘的时候安装Linux,于是试了一下Linux的五种安装方法,下面是我的一些 篇一:安装Linux操作系统的5 ...

  6. 结构型设计模式之组合模式(Composite)

    结构 意图 将对象组合成树形结构以表示“部分-整体”的层次结构.C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性. 适用性 你想表示对象的部分-整体层次结构. 你希望用 ...

  7. 【Tomcat】如何注册Tomcat到Window Service服务

    对于Web项目来说,经常用的服务器就是Tomcat.但是麻烦的事是,每次都得启动一下Tomcat服务.但是,如果把Tomcat的服务注册为Windows Service服务,就可以设置为开机自动启动, ...

  8. 来杯咖啡-装饰者模式(Decorator)

    前言 上篇[观察者模式]发布已经近一个月了,个人感觉反应并不太理想,因为大家响应都不是很积极,不知是文章那里写得有问题,而且也没有人提出过有价值的改进建议,多少感觉有些失望L!因为工作繁忙,所以不可能 ...

  9. JavaScript Promise迷你书(中文版)--再学习

    上次粗翻了一下,感觉没吃透,这次深入体会一下. <script> function getURL(URL) { return new Promise(function(resolve, r ...

  10. 远程服务器的SqlServer允许本地连接

    最近做项目都是直接在阿里云买的服务器,并且SqlServer也是安装好的.但是默认的时候,这个服务器上的SqlServer并不允许直接在本地的SqlServer客户端访问,尽管服务器有公网IP. 想要 ...