前言
在项目中需要开发一个新功能:对Rest服务进行自动化测试。
由于服务的接口定义和测试用例(包括参数名词和值以及返回值)是可以获取的,在测试时可以根据接口定义和测试用例信息构建ajax请求,发送到web服务器(可以是代理服务器)来完成服务的测试。
Rest服务接口参数可以是query(跟在浏览器url地址?后面的),path(跟在浏览器地址/后面的),cookie,header,form,requestBody等类型。然而,理想是丰满的,现实是骨干的,发现浏览器对跨域资源请求是有限制的,本文中主要是浏览器对自定义header参数有约束。因此,只能换方式,构建ajax请求发送到java后端,由java发送rest请求,处理完请求后返回数据给前段,由前段解析数据对比预期返回值来判读测试是否成功。
HttpClient
java后端发起url请求的构件有好几个,由于项目已经包含了HttpClient 4.2的依赖,很自然的使用该构件了。
由于以前没有使用过,第一反应是上网查看HttpClient使用实例,发现没有一个行得通,实例的HttpClient版本和我使用的不一致,没办法,上官网吧。好在HttpClient是apache的项目,文档比较全,每个版本的api和demo都很方便的找到,因此不费吹灰之力就搞定了。
package com.service.controller;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
Import java.io.serializable
@Controller
@RequestMapping("/service/Automation")
public class AutomationServiceController {
@RequestMapping("/run")
@ResponseBody
public JsonResponse RunCase(HttpServletRequest request, HttpServletResponse response){
try{
String url = request.getParameter("url");
String methodDefinition = request.getParameter("methodDefinition");
JSONObject method = JSONObject.parseObject(methodDefinition);
Map<String,String> headerParams= new HashMap<String,String>();
Map<String,String> formParams = new HashMap<String,String>();
Map<String,String> bodyParams = new HashMap<String,String>();
Map<String,String> cookieParams = new HashMap<String,String>();
//参数预处理
if(method.containsKey("params")){
JSONArray params = JSONObject.parseArray(method.getString("params"));
for(int i=0;i<params.size();i++){
JSONObject param = params.getJSONObject(i);
String paramName = param.getString("name");
String paramSource = param.getString("source");
String paramValue = param.getString("value");
switch(paramSource){
case "query":
if(url.indexOf("?")==-1){
url= url+"?"+paramName+"="+paramValue;
}else{
url= url+"&"+paramName+"="+paramValue;
}
break;
case "path":
int paramPathIndex = url.indexOf("{"+paramName+"}");
if(paramPathIndex!=-1){
String tempprefix = url.substring(0,paramPathIndex);
String temppost="";
if(url.length() > paramPathIndex+paramName.length()+2){
temppost = url.substring(paramPathIndex+paramName.length()+2);
}
url = tempprefix+paramValue+temppost;
}
break;
case "header":
headerParams.put(paramName , paramValue);
break;
case "cookie":
cookieParams.put(paramName , paramValue);
break;
case "form":
formParams.put(paramName , paramValue);
break;
case "requestbody":
bodyParams.put(paramName , paramValue);
break;
default:
break;
}
}
}
String methodType = method.getString("type");
String methodConsume = method.getString("consumes");
String data;
//根据方法类型get/post调用不同的处理方法
if("get".equals(methodType)){
data=get(url,headerParams,cookieParams);
}else if ("post".equals(methodType)){
data=post(url,headerParams,formParams,bodyParams,cookieParams,methodConsume);
}else{
return JsonResponse.failure(404, "请求方法出错");
}
if(data!=null){
return JsonResponse.success(data);
}else{
return JsonResponse.failure(500, "运行case出错");
}
}catch(Exception e){
return JsonResponse.failure(500, "运行case出错");
}
}
private String get(String url,Map<String,String> headers,Map<String,String> cookies){
HttpGet get = new HttpGet(url);
return executeHttpRequest(get,headers,cookies);
}
private String post(String url,Map<String,String> headers,Map<String,String> forms,
Map<String,String> bodys,Map<String,String> cookies,String consume){
HttpPost post = new HttpPost(url);
if(forms!=null && forms.size()>0){
List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> form : forms.entrySet()){
NameValuePair nameValuePair = new BasicNameValuePair(form.getKey(), String.valueOf(form.getValue()));
valuePairs.add(nameValuePair);
}
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(valuePairs, "UTF-8");
post.setEntity(formEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else{
//目前只支持一个requestBody来源的参数
if(bodys!=null && bodys.size()>0){
//参数类型是form表单行的,requestBody的值是key-value键值对
if("form".equals(consume)){
List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> body : bodys.entrySet()){
NameValuePair nameValuePair = new BasicNameValuePair(body.getKey(), String.valueOf(body.getValue()));
valuePairs.add(nameValuePair);
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(valuePairs, "UTF-8");
post.setEntity(formEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
break;
}
}else if ("json".equals(consume)){
//参数类型是json类型的,需要设置Content-Type
StringEntity strEntity = null;
post.getParams().setParameter("Content-Type", "application/json");
for(Map.Entry<String,String> body : bodys.entrySet()){
ContentType type = ContentType.create("application/json", Charset.forName("UTF-8"));
strEntity = new StringEntity(body.getValue(),type);
post.setEntity(strEntity);
break;
}
}else if ("xml".equals(consume)){
//参数类型是xml类型的,需要设置Content-Type
StringEntity strEntity = null;
post.getParams().setParameter("Content-Type", "application/xml");
for(Map.Entry<String,String> body : bodys.entrySet()){
ContentType type = ContentType.create("application/xml", Charset.forName("UTF-8"));
strEntity = new StringEntity(body.getValue(),type);
post.setEntity(strEntity);
break;
}
}
}
}
return executeHttpRequest(post, headers, cookies);
}
//发起http请求,解析响应内容
private String executeHttpRequest(HttpRequestBase request,
Map<String,String> headers, Map<String,String> cookies){
DefaultHttpClient client = new DefaultHttpClient();
String response = null;
try {
if(headers!=null && headers.size()>0){
for(Map.Entry<String,String> head : headers.entrySet()){
request.addHeader(head.getKey(), head.getValue());
}
}
if(cookies!=null && cookies.size()>0){
StringBuilder cookieValuePair = new StringBuilder();
for(Map.Entry<String, String> cookie : cookies.entrySet()){
cookieValuePair.append(cookie.getKey()).append("=").append(cookie.getValue()).append(";");
}
request.addHeader("Cookie", cookieValuePair.toString());
}
HttpResponse httpResponse = client.execute(request);
if(httpResponse==null){
return null;
}
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity entity = httpResponse.getEntity();
response = EntityUtils.toString(entity, "UTF-8");
return response;
}else{
return null;
}
} catch (IOException ex) {
logger.error("get请求失败" + request.getURI().toString(), ex);
ex.printStackTrace();
return null;
} finally {
request.releaseConnection();
}
//static class JsonReponse here, implements serializable
}