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

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

我在上一篇文章中已介绍使用第三方工具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

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;

/**
 *  服务入口配置
 * @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();
		}
	}
}

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

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

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;
/**
 *  拦截执行活动请求,返回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("");
        builder.append("" + "cs112233" + "");
        builder.append("" + "230ms" + "");
        builder.append("710302");
        builder.append("1");
        builder.append("1");
        builder.append("1");
        builder.append("0000");
        builder.append("停电公告");
        builder.append("十月31号停电");
        builder.append("20151021101212");
        builder.append("0");
        builder.append("0");
        builder.append("1");
        builder.append("1");
        builder.append(" 管理员 ");
        builder.append("");
        builder.append("");
        builder.append(" 附件1 ");
        builder.append(" 1 ");
        builder.append(" ftp://192.168.1.1/test.doc");
        builder.append("");
        builder.append("");
        builder.append(" 附件2 ");
        builder.append(" 2 ");
        builder.append(" ftp://192.168.1.1/test2.doc");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append(" 20151011121212 ");
        builder.append(" 1 ");
        builder.append(" CP回复测试1 ");
        builder.append("");
        builder.append("");
        builder.append(" 附件1 ");
        builder.append(" ftp://192.168.1.1/test.doc");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append(" 20151011121212 ");
        builder.append(" 2 ");
        builder.append(" 管理员回复测试1 ");
        builder.append("");
        builder.append("");
        builder.append(" 附件1 ");
        builder.append(" ftp://192.168.1.1/test.doc");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
    }
	
}

<2> 处理json格式响应报文,coding如下:
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;

/**
 *  拦截执行活动请求,返回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);
    }
}

重要说明:

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

#配置文件路径
#文件置于当前工程的profile目录下
#ChannelFaqSearch=./profile/ChannelFaqSearch.xml
#ExecuteCampaign=./profile/ExecuteCampaign.json

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

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

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

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;

/**
 *  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;
    }
}

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

package cn.migu.util;

import java.io.*;

/**
 *  读取文件方法封装
 * @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();
    }
}


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

package cn.migu.util;

import org.eclipse.jetty.server.Request;

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

import javax.servlet.http.HttpServletResponse;

/**
 *  响应输出流工具类示例,可自行定制
 * 
 * @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(); }
	 */

}


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


4.注意点

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

以eclipsejar包为例,步骤如下:

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

jetty模拟服务端作为测试桩进行接口测试详细介绍_第1张图片


点击next

jetty模拟服务端作为测试桩进行接口测试详细介绍_第2张图片 


点击finish完成

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

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

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

 

二、测试桩服务器部署

1 部署测试桩环境

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

2>.在配置文件中修改接口地址为对应的测试桩的地址(ipjar包所在服务的主机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平台

你可能感兴趣的:(Java,接口测试)