本章基本实现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");
}
运行上述测试通过