JAVA接口自动化框架2——测试框架的基本实现

本章基本实现java接口自动化框架的基本功能,包括请求,配置,测试类等完整实现

一、parameters包,主要存放请求参数

package com.qa.parameters;

public class Manager {
    private String account;
    private String loginPwd;
    private String partnerCode;
    
    public Manager(){
        
    }
    
    public Manager(String account,String loginPwd,String partnerCode){
        super();
        this.loginPwd=loginPwd;
        this.account=account;
        this.partnerCode=partnerCode;
    }
    
    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    public String getLoginPwd() {
        return loginPwd;
    }
    public void setLoginPwd(String loginPwd) {
        this.loginPwd = loginPwd;
    }
    public String getPartnerCode() {
        return partnerCode;
    }
    public void setPartnerCode(String partnerCode) {
        this.partnerCode = partnerCode;
    }    
}

 

二、base包,存放状态常量,测试类的基类

package com.qa.base;
import org.testng.annotations.BeforeClass;
import com.qa.utils.PropertiesUtils;

/**
 * 该类可以当成所有测试类的模板基类,其他需要测试的类继承该类
 * session,token等需要全局使用的均需要在此类中进行定义;若测试需要登录可在本类进行登录
 * @author jff
 * @date 2018年9月25日
 * @version V1.0.1
 */
public abstract class BaseApi {
    protected String hostManager;
    
    @BeforeClass
    public void setUp() {
        host1=PropertiesUtils.getConfigValue("HOST");
        hostManager=PropertiesUtils.getConfigValue("HOSTMANAGER");
    }
}


package com.qa.base;

/**
 *     常量类,相关的常量都统一放在该类中
 * @author Administrator
 *
 */
public class Constants {
    //不要在代码里写死例状态码,用常量写出来,方便每一个TestNG测试用例去调用去断言
    public static final int RESPNSE_STATUS_CODE_200 = 200;
    public static final int RESPNSE_STATUS_CODE_201 = 201;
    public static final int RESPNSE_STATUS_CODE_204 = 204;
    public static final int RESPNSE_STATUS_CODE_404 = 404;
    public static final int RESPNSE_STATUS_CODE_500 = 500;
}

三、restclient包存放各种请求,包括post,delete,get,put等

package com.qa.restclient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.qa.utils.fatjson.FastjsonUtils;

/*
 * 1.实现get请求方法及带请求头信息,POST请求方法,PUT方法,DELETE方法
 * 2.一个是带请求头信息的POST请求方法
 * 3.获取响应状态码
 * 4.json内容解析
 */
public class RestClient {
	
	private static final Logger log = LoggerFactory.getLogger(RestClient.class);
	
	// get请求方法
	public static CloseableHttpResponse get(String url) throws ClientProtocolException, IOException {
		return get(url, null);
	}

	// Get 请求方法(带请求头信息)
	public static CloseableHttpResponse get(String url, Map headers)
			throws ClientProtocolException, IOException {
		// 创建一个可关闭的HttpClient对象
		CloseableHttpClient httpclient = HttpClients.createDefault();
		// 创建一个HttpGet的请求对象
		HttpGet httpget = new HttpGet(url);
		// 加载请求头到httpget对象
		if (headers != null && headers.size() > 0) {
			for (Map.Entry entry : headers.entrySet()) {
				httpget.addHeader(entry.getKey(), entry.getValue());
			}
		}
		// 执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收
		CloseableHttpResponse httpResponse = httpclient.execute(httpget);

		return httpResponse;
	}
	
	
	//POST方法(如果不需要header可传入null),提交form表单(默认application/x-www-form-urlencoded)
	public static CloseableHttpResponse postForm(String url, Map params, Map headers)
			throws ClientProtocolException, IOException {
		// 设置请求头数据传输格式,使用表单提交的方式,postman中有写
		//headers.put("Content-Type","application/x-www-form-urlencoded");
		return post(url, null, params, headers);
	}

	//  POST方法,发送json格式(如果不需要header可传入null)
	public static CloseableHttpResponse postJson(String url, String jsonString, Map headers)
			throws ClientProtocolException, IOException {
		//准备请求头信息
		headers.put("Content-Type", "application/json");//postman中有写
		return post(url, jsonString, null, headers);
	}	
	
	
	// POST方法
	static CloseableHttpResponse post(String url, String jsonString, Map params, Map headers)
			throws ClientProtocolException, IOException {
		// 创建一个可关闭的HttpClient对象
		CloseableHttpClient httpclient = HttpClients.createDefault();
		// 创建一个HttpPost的请求对象
		HttpPost httppost = new HttpPost(url);
		// 构造请求体,创建参数队列
		if(jsonString != null && !"".equals(jsonString)) {
			httppost.setEntity(new StringEntity(jsonString));
		} else {
			// 构造请求体,创建参数队列
			List nvps = new ArrayList();
			if (params != null && params.size() > 0) {
				for (Map.Entry entry : params.entrySet()) {
					nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
				}
			}
			httppost.setEntity(new UrlEncodedFormEntity(nvps));
		}

		// 加载请求头到httppost对象
		if (headers != null && headers.size() > 0) {
			for (Map.Entry entry : headers.entrySet()) {
				httppost.addHeader(entry.getKey(), entry.getValue());
			}
		}
		// 发送post请求
		CloseableHttpResponse httpResponse = httpclient.execute(httppost);
		return httpResponse;
	}	
	
	
	// 4. Put方法
	public static CloseableHttpResponse put(String url, Map params, Map headers)
			throws ClientProtocolException, IOException {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpPut httpput = new HttpPut(url);
		// 构造请求体,创建参数队列
		List nvps = new ArrayList();
		if (params != null && params.size() > 0) {
			for (Map.Entry entry : params.entrySet()) {
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
		}
		httpput.setEntity(new UrlEncodedFormEntity(nvps));

		// 加载请求头到httpput对象
		if (headers != null && headers.size() > 0) {
			for (Map.Entry entry : headers.entrySet()) {
				httpput.addHeader(entry.getKey(), entry.getValue());
			}
		}
		// 发送put请求
		CloseableHttpResponse httpResponse = httpclient.execute(httpput);
		return httpResponse;
	}

	// 5. Delete方法
	public static CloseableHttpResponse delete(String url) throws ClientProtocolException, IOException {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpDelete httpdel = new HttpDelete(url);

		// 发送put请求
		CloseableHttpResponse httpResponse = httpclient.execute(httpdel);
		return httpResponse;
	}

	/**
	 * 获取响应状态码,常用来和TestBase中定义的状态码常量去测试断言使用
	 * @param response
	 * @return 返回int类型状态码
	 */
	public static int getStatusCode(CloseableHttpResponse response) {
		int statusCode = response.getStatusLine().getStatusCode();
		log.info("解析,得到响应状态码:" + statusCode);
		return statusCode;
	}

	/**把字符串转换为JSON对象,get取出【JSONObject.get("name")】
	 * @param response,
	 *            任何请求返回返回的响应对象 @return, 返回响应体的json格式对象,方便接下来对JSON对象内容解析
	 *            接下来,一般会继续调用TestUtil类下的json解析方法得到某一个json对象的值
	 * @throws ParseException
	 * @throws IOException
	 */
	public static JSONObject getResponseJson(CloseableHttpResponse response) throws ParseException, IOException {
		log.info("得到响应对象的String格式");
		String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
		JSONObject responseJsonObj = FastjsonUtils.toJsonObject(responseString);
		log.info("返回响应内容的JSON对象");
		return responseJsonObj;
	}
	
	/**
	 * 把json字符串转换成指定类型的实体bean
	 * get取出【user.getName()】
	 */
	public static  T getResponseJson2Bean(CloseableHttpResponse response, Class clazz)
			throws ParseException, IOException {
		String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
		log.info("得到响应对象的String格式,数据为:" + responseString);
		T t = FastjsonUtils.toBean(responseString, clazz);
		log.info("返回响应的实体bean对象");
		return t;
	}

}

四、util包存放工具类

1. EntityToMap类

package com.qa.utils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
 * 实体转换map对象
 * @author jff
 * @date 2018年10月15日
 * @version V1.0.1
 */
public class EntityToMap {

	public static Map ConvertObjToMap(Object obj) {
		Map reMap = new HashMap();
		if (obj == null)
			return null;
		Field[] fields = obj.getClass().getDeclaredFields();
		try {
			for (int i = 0; i < fields.length; i++) {
				try {
					Field f = obj.getClass().getDeclaredField(
							fields[i].getName());
					f.setAccessible(true);
					Object o = f.get(obj);
					reMap.put(fields[i].getName(), o);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		return reMap;
	}

}

2. PropertiesUtils类

package com.qa.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 读取系统参数
 * @author jff
 * @date 2018年10月15日
 * @version V1.0.1
 */
public class PropertiesUtils {   
private static Logger log = LoggerFactory.getLogger(PropertiesUtils.class);
	
	private static String configPath = "config.properties";
	private static Properties p = null;
	
	static {
		p = new Properties();
		InputStream is = null;
		try {
			is = PropertiesUtils.class.getClassLoader().getResourceAsStream(configPath);
			p.load(is);
		} catch(Exception ex) {
			log.warn("Failed to load " + configPath + "(ingore this file)" + ex.getMessage());
		} finally {
			if(is != null) {
				try {
					is.close();
				} catch (IOException e) {
					// ingore
				}
			}
		}
	}
	
	/**
	 * 	通过指定的key来获取配置文件中对应的value,支持使用默认值
	 * @param key
	 * @param defValue
	 * @return
	 */
	public static String getConfigValue(String key, String defValue) {
		String value = null;
		try {
			value = p.getProperty(key);
			if(value == null || "".equals(value)) {
				value = defValue;
			}
		} catch (Exception e) {
			log.error("读取配置文件出错,请检查配置文件的路径是否正确!错误信息为:" + e.getMessage());
			value = defValue;
		}
		return value;
	}
	
	/**
	 * 	通过指定的key来获取配置文件中对应的value,支持使用默认值
	 * @param key
	 * @return
	 */
	public static String getConfigValue(String key) {
		return getConfigValue(key, null);
	}
}

五、utils.fatjson包,也是工具包的一种,专门提供fastjson的包

1. CustomFilter类

package com.qa.utils.fatjson;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;

/**
 * 属性序列化过滤器
 * 
 * @author Mr.chen 
 * @since 1.0.0
 */
@SuppressWarnings("unchecked")
public class CustomFilter implements PropertyPreFilter {

	private Map, String[]> includes = new HashMap, String[]>(); // 需要序列化的属性
	private Map, String[]> excludes = new HashMap, String[]>(); // 不需要序列化的属性

	public CustomFilter() {

	}
	
	public CustomFilter(Map, String[]> excludes) {
		this(Collections.EMPTY_MAP,excludes);
	}
	
	public CustomFilter(Map, String[]> includes,Map, String[]> excludes) {
		this.includes = includes;
		this.excludes = excludes;
	}

	@Override
	public boolean apply(JSONSerializer serializer, Object source, String name) {
		// 对象为空。直接放行
		if (source == null) {
			return true;
		}
		// 获取当前需要序列化的对象的类类型
		Class clazz = source.getClass();
		if(!this.excludes.isEmpty()){
			return isNeed(clazz,this.excludes,name);
		}else if(!this.includes.isEmpty()){
			return isNeed(clazz,this.includes,name);
		}else{
			return true;
		}

	}
	
	/**
	 * @Description 判断是否需要序列化
	 * @param clazz 类类型
	 * @param map 需要序列化或不需要序列化的属性集合
	 * @param name 放射得到的javaBean中的属性
	 * @return 布尔值
	 */
	private boolean isNeed(Class clazz,Map,String[]> map,String name){
		boolean isNeed = true;
		for (Map.Entry, String[]> item : map.entrySet()) {
			/*
			 *  isAssignableFrom():
			 *  	判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,
			 *  	或是否是其超类或超接口。
			 */
			if (item.getKey().isAssignableFrom(clazz)) {
				String[] strs = item.getValue();
				// 该类型下 此 name 值无需序列化
				if (isHave(strs, name)) {
					if(map == this.excludes){
						isNeed = false;
					}
				}
			}
		}
		return isNeed;
	}

	/**
	 * @Description 判断数组中是否包含指定的字符或字符串
	 * @param strs 字符串数组
	 * @param str 要查找的字符或字符串
	 * @return 布尔值
	 */
	private boolean isHave(String[] strs, String str) {
		for (int i = 0; i < strs.length; i++) {
			// 循环查找字符串数组中的每个字符串中是否包含所有查找的内容
			if (strs[i].equals(str)) {
				// 查找到了就返回真,不在继续查询
				return true;
			}
		}
		// 没找到返回false
		return false;
	}

	public Map, String[]> getIncludes() {
		return includes;
	}

	public void setIncludes(Map, String[]> includes) {
		this.includes = includes;
	}

	public Map, String[]> getExcludes() {
		return excludes;
	}

	public void setExcludes(Map, String[]> excludes) {
		this.excludes = excludes;
	}

}

2.FastjsonUtils类

package com.qa.utils.fatjson;

import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.qa.parameters.Users;

/**
 * json 解析工具类
 * @author Administrator
 *
 */
public class FastjsonUtils {

	@SuppressWarnings("unchecked")
	public static Map toMap(String json) {
		return JSON.parseObject(json, Map.class);
	}
	
	private static SerializerFeature[] features = null;

	// ==================================toJson========================

	/**
	 * 最简单的json转换方法
	 * 
	 * @param obj
	 *            需要序列化的对象
	 * @return json字符串
	 */
	public static String toJson(Object obj) {
		return toJson(false, null, obj, null);
	}

	/**
	 * 默认配置的json转换方法
	 * 
	 * @param obj
	 *            需要序列化的对象
	 * @param cf
	 *            过滤器
	 * @return json字符串
	 */
	public static String toJson(Object obj, CustomFilter cf) {
		return toJson(false, null, obj, cf);
	}
	
	/**
	 * 将属性值为null的属性不进行序列化显示
	 * @param obj
	 * 			  需要序列化的对象
	 * @return
	 */
	public static String toJsonWithOutNull(Object obj) {
		return toJsonForRemove(new SerializerFeature[]{SerializerFeature.WriteMapNullValue}, obj, null);
	}

	/**
	 * 移除格式化参数配置后的json转换方法
	 * 
	 * @param rmFeatures
	 *            需要移除的格式化参数配置
	 * @param obj
	 *            需要序列化的对象
	 * @param cf
	 *            过滤器
	 * @return json字符串
	 */
	public static String toJsonForRemove(SerializerFeature[] rmFeatures,Object obj, CustomFilter cf) {
		return toJson(false, rmFeatures, obj, cf);
	}

	/**
	 * 加入格式化参数配置后的json转换方法
	 * 
	 * @param addFeatures
	 *            需要添加的格式化参数配置
	 * @param obj
	 *            需要序列化的对象
	 * @param cf
	 *            过滤器
	 * @return json字符串
	 */
	public static String toJsonForAdd(SerializerFeature[] addFeatures,Object obj, CustomFilter cf) {
		return toJson(true, addFeatures, obj, cf);
	}

	/**
	 * 具体的json转换方法
	 * 
	 * @param isAdd
	 *            选择添加还是移除操作
	 * @param myFeatures
	 *            需要操作的格式化参数配置
	 * @param obj
	 *            需要序列化的对象
	 * @param cf
	 *            过滤器
	 * @return json字符串
	 */
	public static String toJson(boolean isAdd,SerializerFeature[] myFeatures, Object obj, CustomFilter cf) {
		isAdd(isAdd, myFeatures);
		features = FeaturesUtil.getFeatureArray();
		return JSON.toJSONString(obj, cf, features);
	}
	
	public static JSONObject toJsonObject(String json) {
		return JSON.parseObject(json);
	}

	// parse to java object
	public static Object parseObject(String jsonString) {
		return toBean(jsonString, Object.class);
	}

	// parse to java bean
	public static  T toBean(String jsonString, Class clazz) {
		return JSON.parseObject(jsonString, clazz);
	}

	// parse to java bean list
	public static  List toBeanList(String jsonString, Class clazz) {
		return JSON.parseArray(jsonString, clazz);
	}

	// -----------------------------------私有方法部分---------------------------------------

	/**
	 * 本类的私有的方法
	 * 
	 * @param isAdd
	 *            是否调用add方法
	 * @param _features
	 *            格式化参数配置数组
	 */
	private static void isAdd(boolean isAdd, SerializerFeature[] _features) {
		if (_features != null && _features.length > 0) {
			for (SerializerFeature sf : _features) {
				if (isAdd) {
					FeaturesUtil.add(sf);
				} else {
					FeaturesUtil.remove(sf);
				}
			}
		}
	}

	public static void main(String[] args) {
		String Json="{\"name\":\"jffhy\",\"job\":\"tester\"}";
		//Users user=toBean(Json, Users.class);
		//System.out.println(user.getJob());
		
		JSONObject json=toJsonObject(Json);
		System.out.println(json.getString("name"));
	}

}

3. FeaturesUtil类

package com.qa.utils.fatjson;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.serializer.SerializerFeature;

/**
 * 序列化格式设置参数配置
 * 
 * @author Mr.chen 
 * @since 1.0.0
 */
public class FeaturesUtil {
	
	private static List features = new ArrayList();
	
	// 默认参数配置
	static {
		features.add(SerializerFeature.DisableCircularReferenceDetect);  // 取消引用代替配置
		features.add(SerializerFeature.WriteDateUseDateFormat);  // 使用日期格式化配置
		features.add(SerializerFeature.WriteMapNullValue);  // map中键对应值为null时用""代替的配置
//		features.add(SerializerFeature.WriteNullNumberAsZero); //将空数值用"0"来代替的配置
		features.add(SerializerFeature.WriteNullListAsEmpty); // 将空集合用"[]"来代替的配置
		features.add(SerializerFeature.WriteNullStringAsEmpty); // 将空字符串用""代替的配置
	}
	
	/**
	 * 添加序列化格式参数
	 * 
	 * @param feature
	 */
	public static void add(SerializerFeature feature){
		if(feature !=null){
			features.add(feature);
		}
	}
	
	/**
	 * 移除序列化格式参数
	 * 
	 * @param feature
	 */
	public static void remove(SerializerFeature feature){
		if(feature !=null){
			if(features.contains(feature)){
				features.remove(feature);
			};
		}
	}
	
	/**
	 * 获取配置参数集合对象
	 * 
	 * @return list of SerializerFeature
	 */
	public static List getFeatures(){
		return features;
	}
	
	/**
	 * 获取配置参数数组对象
	 * 
	 * @return array of SerializerFeature
	 */
	public static SerializerFeature[] getFeatureArray(){
		return features.toArray(new SerializerFeature[]{});
	}

}

六、resources资源包

1.config.properties   存放host

HOSTMANAGER=http://xx.test.mwpark.cn

 

2.log4j.properties   

### set log levels ###
log4j.rootLogger = INFO, stdout, file

##log4j.appender.syslog.encoding=UTF-8
log4j.appender.file.encoding=UTF-8
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss SSS} %-5p %c{1}:%L - %m%n
 
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = ./log/apilog.log
# overwirte the old log file
log4j.appender.file.Append = false      
## 
log4j.appender.file.Threshold = INFO
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss SSS} %-5p %c{1}:%L - %m%n

七、test测试包

package manager;
import java.io.IOException;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.alibaba.fastjson.JSONObject;
import com.qa.base.BaseApi;
import com.qa.base.Constants;
import com.qa.parameters.Manager;
import com.qa.restclient.RestClient;
import com.qa.utils.fatjson.FastjsonUtils;

public class LoginManagerAppTest2 extends BaseApi{
    private final static Logger Log=Logger.getLogger(LoginManagerAppTest2.class);
    
    @Test
    public void loginManagerAppTest1() throws ClientProtocolException, IOException{
        String url=hostManager+"/parkingManager/applogin/loginIn";
        Manager manager = new Manager("yanczapp","8ddcff3a80f4189ca1c9d4d902c3c909","0571001");
        Map map=FastjsonUtils.toMap(FastjsonUtils.toJson(manager));
        System.out.println("my out**********"+map);
        CloseableHttpResponse closeableHttpResponse = RestClient.postForm(url, map, null);
        
        //断言状态码是不是200
        int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
        Assert.assertEquals(statusCode,Constants.RESPNSE_STATUS_CODE_200,"status code is not 200");
    
        //断言响应json内容中name和job是不是期待结果
        String responseString = EntityUtils.toString(closeableHttpResponse.getEntity());
        System.out.println("my out**********"+responseString);
        JSONObject res  = FastjsonUtils.toJsonObject(responseString);
        sessionKey = FastjsonUtils.toMap(res.getString("data")).get("session_key");
        System.out.println("data**********: " + res.getString("message"));
        System.out.println("data**********: " + sessionKey);
        
        String account=FastjsonUtils.toMap(res.getString("data")).get("account");
        Assert.assertEquals(account,"yanczapp" ,"account code is not error");
    }

运行上述测试通过

你可能感兴趣的:(JAVA接口自动化测试框架)