1. 程式人生 > >jetty模擬服務端作為測試樁進行介面測試詳細介紹

jetty模擬服務端作為測試樁進行介面測試詳細介紹

有時,在進行介面測試時,很多時候需要依賴外部的介面環境,但在實際開發中,尤其是敏捷開發模式中,很多時候依賴的外部介面環境可能不通或者未開發完畢,這時候無法及時進行端到端的測試,測試樁的必要性就非常重要了。

但由於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.javamain方法,瀏覽器中輸入main方法中配置的請求路徑http://localhost:19993/test/ChannelFaqSearch(我本機跑,iplocalhost,佈置到伺服器,換成伺服器ip),就可以看到返回的報文了。

4.注意點

在伺服器上打包執行,打包時注意main函式的選取(選自己寫的要啟動的埠對應的java類)。

以eclipsejar包為例,步驟如下:

右鍵選中測試樁工程 --> export -->


點選next

 

點選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包時報錯,注意是否是埠號被佔用

#知識傳送門:

以上是我寫的用於測試樁的mock平臺,非常簡單易懂,直接將專案打成war包部署tomcat容器即可執行。

該平臺通過前臺web頁面管理介面,可作為輕量級的mock平臺