您的位置:首页 > 其它

jetty模拟服务端作为测试桩进行接口测试详细介绍

2016-08-19 09:41 573 查看
有时,在进行接口测试时,很多时候需要依赖外部的接口环境,但在实际开发中,尤其是敏捷开发模式中,很多时候依赖的外部接口环境可能不通或者未开发完毕,这时候无法及时进行端到端的测试,测试桩的必要性就非常重要了。

我在上一篇文章中已介绍使用第三方工具SoapUI做为模拟服务端作为测试桩进行接口测试,详见http://blog.csdn.net/russ44/article/details/52230355
但由于SoapUI通常部署在本地的Windows环境上(linux环境本人未使用过,不建议),而测试环境通常部署在linux服务器上,可能存在测试环境无法调通本地环境的情况,这时就需要另一种方式部署到linux服务器进行接口测试,详细如下:

一、测试桩项目介

1. jetty介绍:

Jetty 是一个开源的servlet容器,它为基于Java的web容器,易用性是
Jetty 设计的基本原则,详情可百度之

所需jar包(本人):



2. 测试桩目的:

测试人员在测试中,尤其是进行接口测试时,经常需要使用到测试桩来进行测试,通常情况下,相应的开发人员会写好相应的测试桩,以jar包的形式作为一个服务端给客户端进行调用(当接口联调未能按计划进行或延迟时,测试人员应主导向开发人员要求提供测试桩进行测试,具体视实际情况而定)

 

3. 测试桩原理

相当于启动一个jetty容器,拦截对应的请求,返回相应的报文。

 

4. 测试桩使用过程

1.在server包下写一个带main函数(这个main函数会启动一个jetty容器)的java类,配置端口号,想要拦截的请求,和对应的处理请求的servlet

<span style="font-size:18px;">package cn.migu.server;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import cn.migu.servlet.JsonResponseDemo;
import cn.migu.servlet.XmlResponseDemo;
import cn.migu.util.Log4jUtil;

/**
* <Description> 服务入口配置
* @author YanLu
*
*/
public class HttpServerDemo {

//private static Log4jUtil log = new Log4jUtil(HttpServerDemo.class.getName());

/**
* main方法入口
*
* @param args
*/
public static void main(String[] args) {
try {
Server server = new Server(19993);
// 指定服务的端口号

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
// 一个context就是一个WEB-Application

context.setContextPath("/test");
// 访问项目名(路径)

server.setHandler(context);
// servlet映射的路径,类似于web.xml的servlet url-pattern定义

context.addServlet(new ServletHolder(new XmlResponseDemo()), "/ChannelFaqSearch");
// 两个参数分别为拦截请求的servlet和想要拦截的路径
context.addServlet(new ServletHolder(new JsonResponseDemo()), "/ExecuteCampaign");
//log.info("server start.");
System.out.println("server start.");

// 启动服务
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
</span>


2.在servlet中处理请求,返回报文(测试桩主要目的是模拟接口,返回报文。请求处理啥的就掠过啦~)

<1> 处理xml格式响应报文,coding如下:

<span style="font-size:18px;">package cn.migu.servlet;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.migu.util.ConfigUtil;
import cn.migu.util.GlobalSettings;
import cn.migu.util.Log4jUtil;
import cn.migu.util.OutPrinterUtil;
import cn.migu.util.XMLReaderHelper;
/**
* <Description> 拦截执行活动请求,返回xml格式报文
* @author YanLu
*
*/
public class XmlResponseDemo extends HttpServlet {

//private Log4jUtil log = new Log4jUtil(this.getClass().getName());

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
StringBuilder builder;

//String filePath = "/apps/stub_test/responseProfile/ChannelFaqSearch.xml";
//String filePath = GlobalSettings.getProperty("ChannelFaqSearch");
//读取外部的xml文件
String filePath = ConfigUtil.CONFIG.get("ChannelFaqSearch");
//将xml文件转化为String
String xmlStr = XMLReaderHelper.xmlStrReader(filePath);
if (!(null == xmlStr)) {
System.out.println("读取XML成功!");
builder = new StringBuilder(xmlStr);
} else {
System.out.println("读取XML失败!");
builder = new StringBuilder(1024);
bindBuilder(builder);
}
//响应xml格式字符串
OutPrinterUtil.outputXml(response, builder);
}

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//同doPost方法
doPost(request, response);
}

private void bindBuilder(StringBuilder builder) {
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?><notifyRsp>");
builder.append("<transId>" + "cs112233" + "</transId>");
builder.append("<processTime>" + "230ms" + "</processTime>");
builder.append("<cpId>710302</cpId>");
builder.append("<bulletinType>1</bulletinType>");
builder.append("<bulletinID>1</bulletinID>");
builder.append("<bulletinID>1</bulletinID>");
builder.append("<returnCode>0000</returnCode>");
builder.append("<bulletinTitle>停电公告</bulletinTitle>");
builder.append("<bulletinCont>十月31号停电</bulletinCont>");
builder.append("<publishTime>20151021101212</publishTime>");
builder.append("<publishType>0</publishType>");
builder.append("<bulletinLevel>0</bulletinLevel>");
builder.append("<contactType>1</contactType>");
builder.append("<needReply>1</needReply>");
builder.append("<adminName> 管理员 </adminName >");
builder.append("<bulletinAttachs>");
builder.append("<bulletinAttach>");
builder.append("<attachName> 附件1 </attachName >");
builder.append("<attachType> 1 </attachType >");
builder.append("<attachURL> ftp://192.168.1.1/test.doc</attachURL>"); builder.append("</bulletinAttach>");
builder.append("<bulletinAttach>");
builder.append("<attachName> 附件2 </attachName >");
builder.append("<attachType> 2 </attachType >");
builder.append("<attachURL > ftp://192.168.1.1/test2.doc</attachURL>"); builder.append("</bulletinAttach >");
builder.append("</bulletinAttachs >");
builder.append("<replys >");
builder.append("<reply >");
builder.append("<replyTime > 20151011121212 </replyTime >");
builder.append("<replyType > 1 </replyType >");
builder.append("<replyCont > CP回复测试1 </replyCont >");
builder.append("<replyAttchs >");
builder.append("<replyAttch >");
builder.append("<attachName > 附件1 </attachName >");
builder.append("<attachURL > ftp://192.168.1.1/test.doc</attachURL>"); builder.append("</replyAttch >");
builder.append("</replyAttchs >");
builder.append("</reply >");
builder.append("<reply >");
builder.append("<replyTime > 20151011121212 </replyTime >");
builder.append("<replyType > 2 </replyType >");
builder.append("<replyCont > 管理员回复测试1 </replyCont >");
builder.append("<replyAttchs >");
builder.append("<replyAttch >");
builder.append("<attachName > 附件1 </attachName >");
builder.append("<attachURL > ftp://192.168.1.1/test.doc</attachURL>"); builder.append("</replyAttch >");
builder.append("</replyAttchs >");
builder.append("</reply >");
builder.append("</replys >");
builder.append("</notifyRsp>");
}

}
</span>

<2> 处理json格式响应报文,coding如下:
<span style="font-size:18px;">package cn.migu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.migu.util.ConfigUtil;
import cn.migu.util.FileUtil;
import cn.migu.util.GlobalSettings;
import cn.migu.util.OutPrinterUtil;

import java.io.IOException;

/**
* <Description> 拦截执行活动请求,返回json格式报文
* @author YanLu
*
*/
public class JsonResponseDemo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//String filePath = "/apps/stub_test/responseProfile/ExecuteCampaign.json";
String filePath = ConfigUtil.CONFIG.get("ExecuteCampaign");

//将json文件转化为String
String resultJson= FileUtil.ReadFile(filePath);

//响应json格式字符串
OutPrinterUtil.outputJson(resultJson, resp);
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
</span>


重要说明:

<1>  文件存放位置如下:

<span style="font-size:18px;">#配置文件路径
#文件置于当前工程的profile目录下
#ChannelFaqSearch=./profile/ChannelFaqSearch.xml
#ExecuteCampaign=./profile/ExecuteCampaign.json

#文件置于与项目同级的目录下
ChannelFaqSearch=./responseProfile/ChannelFaqSearch.xml
ExecuteCampaign=./responseProfile/ExecuteCampaign.json

#文件路径为按绝对路径
#ChannelFaqSearch=/apps/responseProfile/ChannelFaqSearch.xml</span>


<2> xml文件转化为String的代码如下:

<span style="font-size:18px;">package cn.migu.util;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
* <Description> XMLReader帮助类
* @author YanLu
*
*/
public class XMLReaderHelper {
private static Document document;

//将xml文件转换为String,使用dom方式解析xml
public static String xmlStrReader(String fileName) {
try {
//获取DOM解析器工厂,以便生产解析器
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//获取DOM解析器,以便解析DOM
DocumentBuilder db = dbf.newDocumentBuilder();

//把要解析的 XML 文档转化为输入流,以便 DOM 解析器解析它
//InputStream is= new  FileInputStream("test1.xml");

//解析 XML 文档的输入流,得到一个 Document
document = db.parse(fileName);

TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
t.transform(new DOMSource(document), new StreamResult(bos));
String xmlStr = bos.toString();
return xmlStr;
} catch (ParserConfigurationException e) {
System.err.println(e.getMessage());
} catch (SAXException e) {
System.err.println(e.getMessage());
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (TransformerConfigurationException e) {
System.err.println(e.getMessage());
} catch (TransformerException e) {
System.err.println(e.getMessage());
}
return null;
}
}
</span>


<3> json文件转换String代码如下:

<span style="font-size:18px;">package cn.migu.util;

import java.io.*;

/**
* <Description> 读取文件方法封装
* @author YanLu
*
*/
public class FileUtil {

/**
* 读取.json文件方法
* @param filePath
* @return
*/
public static String ReadFile(String filePath) {
BufferedReader reader=null;
StringBuilder result=null;
try {
FileInputStream inStream=new FileInputStream(filePath);
InputStreamReader inReader=new InputStreamReader(inStream,"UTF-8");
reader=new BufferedReader(inReader);
result=new StringBuilder();
String tempStr;
while((tempStr=reader.readLine())!=null){
result.append(tempStr);
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(reader!=null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result.toString();
}
}
</span>


<4> 输出响应报文代码如下:

<span style="font-size:18px;">package cn.migu.util;

import org.eclipse.jetty.server.Request;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;

/**
* <Description> 响应输出流工具类示例,可自行定制
*
* @author YanLu
*
*/
public class OutPrinterUtil {

/**
* 响应xml格式字符串
*
* @param response
* @param result
* @throws IOException
*/
public static void outputXml(HttpServletResponse response, StringBuilder result) throws IOException {
// response.setContentType("application/xml");
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
System.err.println("响应码为:"+HttpServletResponse.SC_OK);
PrintWriter pw = response.getWriter();
pw.print(result.toString());
pw.flush();
pw.close();
}

/**
* 响应json格式字符串
*
* @param json
* @param response
*/
public static void outputJson(String json, HttpServletResponse response) {
try {
response.setCharacterEncoding("UTF-8");
// json串必须要是json格式,否则会出错
response.setContentType("application/json");

//在代理服务器端防止缓冲
response.setDateHeader("Expires", 0);
PrintWriter out = response.getWriter();
out.print(json);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 需要返回给用户的结果不支持session
*
* @param baseRequest
* @param response
* @param result
* @throws IOException
*/
public static void outputNoSession(Request baseRequest, HttpServletResponse response, String result)
throws IOException {
response.setContentType("text/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println(result);
}

/*
* private OutPrinterUtil() { super(); }
*/

}
</span>


3.测试桩运行。以HttpServerDemo为例,启动HttpServerDemo.java的main方法,浏览器中输入main方法中配置的请求路径http://localhost:19993/test/ChannelFaqSearch(我本机跑,ip为localhost,布置到服务器,换成服务器ip),就可以看到返回的报文了。

4.注意点

在服务器上打包运行,打包时注意main函数的选取(选自己写的要启动的端口对应的java类)。

以eclipse打jar包为例,步骤如下:

右键选中测试桩工程 --> export -->



点击next


 

点击finish完成

然后将打好的jar包(如jettyServer.jar)上传至服务器

即可命令运行jar包(先给jar文件赋权限,否者可能无法执行)。

例:命令如下:java -jar jettyServer.jar

 

二、测试桩服务器部署

1 部署测试桩环境

1>.测试桩完成后打为jar包,需确认包中定义的相关端口号,及测试桩的请求路径。

2>.在配置文件中修改接口地址为对应的测试桩的地址(ip为jar包所在服务的主机ip,端口为定义的端口)

3>.将jar包部署到服务器(我目前在192.168.129.145服务器上建立了一个目录作为测试桩的存放路径:/apps/stub_test/大家可以统一将jar包放置此处,当然也可以自定义)

2 启动关闭测试桩

Linux上启动测试桩命令:

1>.#java -jar testStub.jar &   

//该命令表示启动jar包

//注:加&表示将进程放置在后台运行

 

2>.#jobs                    

//查看后台运行的任务列表

 

3>.#nohup java -jar testStub.jar &

//如果想在退出终端后服务不终止则使用nohup命令,nohup的作用是即使退出终端,程序仍不会结束,使用nohup命令应注意该服务不会停止,不用时应注意将该进程kill


 

//若出现下面提示信息,不是报错,它表示程序运行信息会输出到nohup.out

#nohup: ignoring input and appending output to `nohup.out'

 

4>.#jobs -l

 


如图所示,显示该服务的进程号

 

#kill -9 进程号

//干掉进程

 

3 注意事项

1>.在使用测试桩时,返回报文是作为一个xml(或json)文件放在外部进行读取的,这样便于测试在测试时可通过修改xml文件的形式进行更多场景的测试

2>.如果在启动jar包时报错,注意是否是端口号被占用

#知识传送门:

https://github.com/russ44/easyMock

以上是我写的用于测试桩的mock平台,非常简单易懂,直接将项目打成war包部署tomcat容器即可运行。

该平台通过前台web页面管理接口,可作为轻量级的mock平台
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: