jetty模拟服务端作为测试桩进行接口测试详细介绍
来源:互联网 发布:淘宝清理缓存后会怎样 编辑:程序博客网 时间:2024/05/22 13:37
有时,在进行接口测试时,很多时候需要依赖外部的接口环境,但在实际开发中,尤其是敏捷开发模式中,很多时候依赖的外部接口环境可能不通或者未开发完毕,这时候无法及时进行端到端的测试,测试桩的必要性就非常重要了。
我在上一篇文章中已介绍使用第三方工具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-Applicationcontext.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文件转化为StringString 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.xmlExecuteCampaign=./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://git.oschina.net/russ44/easyTest
以上是我写的用于测试桩的平台,直接将项目部署tomcat容器即可运行。通过前台页面管理接口,分享给大家使用
- jetty模拟服务端作为测试桩进行接口测试详细介绍
- SoapUI模拟服务端进行接口测试
- SoapUI模拟服务端进行接口测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- Loadrunner模拟JSON接口请求进行测试
- 服务端接口测试小结
- 服务端测试之接口测试初探
- SOAPUI作为测试端测试接口调用
- Python对Http接口进行多线程模拟压力测试
- 使用jetty-maven-plugin插件进行测试
- 使用jetty-maven-plugin插件进行测试
- 接口测试-Swagger介绍
- 接口测试介绍
- Mysql各种存储引擎的特性以及如何选择存储引擎
- ProgressDialog dismiss not attached to window manager
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- 对系统自带的框架MapKit的应用
- assets路径 资源uri
- jetty模拟服务端作为测试桩进行接口测试详细介绍
- HTTP协议由浅入深
- [Leetcode #1]Two Sum 从数组中找出和为特定值的两个数
- iOS企业级开发者账号申请
- 主从复制、备份恢复方案生产环境实战
- 组合查询--机房收费系统
- netstat -anu|grep 69命令详解
- MyBatis+Oracle简单用户的增加、删除、查询
- Java编程思想高清下载