我們在接口自動化測試過程中,或多或少會遇到當比較接口返回結果時,如果將結果作為一個整體的對象進行比較,假如斷言失敗時,那我們將會看到一大坨期望和實際結果數據,很難一眼就看出具體是因為哪一部分不一致而導致的比對失敗,這也增加了我們的接口自動化維護成本。
本文主要圍繞這一痛點,解決 JsonObject、JSONArray、String、Integer 對象的精確比較問題,並提供統一的Java實現方法 Compare.CompareFactory,希望對大家有所幫助。
先睹為快,讓我們直接來看下效果如何,此外,文末附 Python 具體實現設計。
JSONObject 對象的一致性比對
如下,先準備兩個測試數據,我們可以看到測試數據的結構還是比較複雜的,其中左側和右側不一致的地方共有7處,如黃色框處的位置。
首先看一下,如果直接斷言,我們看到的結果是什麼樣的。
正如開篇所提,想要找出其中的不同,實在... 簡直... 。
然後,使用 Compare.CompareFactory 方法,執行過程中的打印結果如下,我們可以看到每個節點的比較結果都非常清晰的打印出來了,並且key 的描述也是含
JSON層級關係的,如 "regional.city[0]" 。再然後,看下 Compare.CompareFactory 方法的返回結果,我們將返回對象使用JSONObject.toJSONString 轉換成字符串後,如下,resultDetail 屬性記錄了每個錯誤節點的期望和實際數據值,
wrongNumber 屬性統計了錯誤數量,清晰明瞭,簡單直白。最後,看下代碼,因為我將測試數據放到 yaml 文件中,因為其中部分代碼是在加載測試數據。
JSONArray 對象的一致性比對
首先,準備如下兩個測試數據,其中左側和右側不一致的地方共有 5 處,如黃色框處的位置。
然後,使用 Compare.CompareFactory 方法,執行過程中的打印結果如下:
再然後,我們看下 Compare.CompareFactory 方法的返回結果,如下:
最後,我們看下示例代碼,因為我將測試數據放到Yaml文件中,所以其中部分代碼是在加載測試數據。
String、Integer、Long 對象的一致性比對
String、Integer、Long 對象的比對,同樣也是使用 Compare.CompareFactory 方法完成,示例代碼如下:
因為String、Integer、Long不存在KV映射,因此比較結果中key顯示為null。如下:
還提供了哪些特性?
肯定有小夥伴會問,在做接口返回結果的校驗時,並不是全部的數據都需要一一進行比對,比如時間屬性,因為每次可能返回的時間不同,但本身不影響結果的準確性,所以不需要進行比較。 那Compare.CompareFactory 方法是否不支持過濾某些屬性不比較呢?——那當然是支持的咯,細心的小夥伴 Compare.CompareFactory 的有三個參數,那第三個是幹嘛的呢?其實第三個參數就是描述需要過濾的屬性的,如果需要過濾多個屬性使用英文逗號隔開即可。
比如,我們將上圖例子中的實際和期望結果不一致的 code、designation、hobby_id、desc 4個屬性過濾掉不比較,代碼如下。
運行代碼,我們可以看到比對結果中,只存在三處不一致的地方,即實現了過濾比較。
核心源碼
最後,如何獲取全部源碼? 因文章無法上傳Git鏈接,需要源碼的小夥伴可以私聊我,記得關注、點贊支持一下哦。
因涉及多個java文件,這裡只能貼出核心代碼,如下:
<code> import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;
public class Compare {
private static BaseResult baseResult;
/**
* @Description: 更新結果,錯誤數量計數
* @Param: [parameter]
* @Author:
* @DateTimeFormat: 2020/3/8
*/
private static void updateBaseResult(ResultDetail resultDetail) {
// 錯誤數量統計
baseResult.setWrongNumber(baseResult.getWrongNumber() + 1);
// 填充 RetValue 錯誤內容
if (baseResult.getResultDetail() == null) {
ArrayList<resultdetail> resultDetailArrayList = new ArrayList<resultdetail>();
resultDetailArrayList.add(resultDetail);
baseResult.setResultDetail(resultDetailArrayList);
} else {
baseResult.getResultDetail().add(resultDetail);
}
}
/**
* @Description: 字符串比較
* @Param: [parameter]
* @return: void
* @Author: YJiang
* @DateTimeFormat: 2020/3/8
*/
private static void compareJson(String actualString, String expectString, String key, String prefix , String ignore) {
boolean status = false;
if (StringUtils.isNotBlank(ignore)) {
List<string> listIgnore = Arrays.asList(ignore.split(","));
status = listIgnore.contains(key);
}
if (!status) {
if (!actualString.equals(expectString)) {
ResultDetail resultDetail = new ResultDetail(prefix, actualString, expectString, "Value Not Equal");
updateBaseResult(resultDetail);
System.out.println(
"\\033[1;31m" + "【fail】Key:" + prefix + "\\n actualJson:" + actualString + "\\n expectJson:" + expectString + "\\033[m");
} else {
System.out.println(
"\\033[1;94m" + "【success】Key:" + prefix + "\\n actualJson:" + actualString + "\\n expectJson:" + expectString + "\\033[m");
}
}
}
/**
* @Description: JSONObject 比較
* @Param: [parameter]
* @return: void
* @Author: YJiang
* @DateTimeFormat: 2020/3/8
*/
private static void compareJson(JSONObject actualJson, JSONObject expectJson, String key,String prefix, String ignore) {
if (StringUtils.isBlank(prefix)){
prefix = "";
}else {
prefix = prefix + ".";
}
for (String s : expectJson.keySet()) {
key = s;
compareJson(actualJson.get(key), expectJson.get(key), key, prefix + key, ignore);
}
}
/**
* @Description: JSONArray 比較
* @Param: [parameter]
* @return: void
* @Author: YJiang
* @DateTimeFormat: 2020/3/8
*/
private static void compareJson(JSONArray actualJsonArray, JSONArray expectJsonArray, String key,String prefix, String ignore) {
if (actualJsonArray != null && expectJsonArray != null) {
if (actualJsonArray.size() == expectJsonArray.size()) {
Iterator iteratorActualJsonArray = actualJsonArray.iterator();
if (StringUtils.isBlank(prefix)){
prefix = "";
}
int num = 0;
for (Object o : expectJsonArray) {
compareJson(iteratorActualJsonArray.next(), o, key,prefix+"["+num+"]", ignore);
num ++;
}
} else {
ResultDetail resultDetail = new ResultDetail(prefix, actualJsonArray, expectJsonArray, "Length Not Equal");
updateBaseResult(resultDetail);
}
} else {
if (actualJsonArray == null && expectJsonArray == null) {
ResultDetail resultDetail = new ResultDetail(prefix, "在 actualJsonArray 中不存在",
"在 expectJsonArray 中不存在",
"Both Not Exist");
updateBaseResult(resultDetail);
} else if (actualJsonArray == null) {
ResultDetail resultDetail = new ResultDetail(prefix, "在 actualJsonArray 中不存在", expectJsonArray,
"Other Exist");
updateBaseResult(resultDetail);
} else {
ResultDetail resultDetail = new ResultDetail(prefix, actualJsonArray, "在 expectJsonArray 中不存在",
"Other Exist");
updateBaseResult(resultDetail);
}
}
}
/**
* @Description: Object 比較
* @Param: [parameter]
* @return: void
* @Author: YJiang
* @DateTimeFormat: 2020/3/8
*/
private static void compareJson(Object actualJson, Object expectJson, String key,String prefix, String ignore) {
if (actualJson != null && expectJson != null) {
if (actualJson instanceof JSONObject) {
compareJson((JSONObject)actualJson, (JSONObject)expectJson, key,prefix, ignore);
} else if (actualJson instanceof JSONArray) {
compareJson((JSONArray)actualJson, (JSONArray)expectJson, key,prefix, ignore);
} else if (actualJson instanceof String) {
try {
String actualJsonToStr = actualJson.toString();
String expectJsonToStr = expectJson.toString();
compareJson(actualJsonToStr, expectJsonToStr, key,prefix, ignore);
} catch (Exception e) {
ResultDetail resultDetail = new ResultDetail(prefix, actualJson, expectJson, "String 轉換髮生異常 Key");
updateBaseResult(resultDetail);
e.printStackTrace();
}
} else {
compareJson(actualJson.toString(), expectJson.toString(), key,prefix, ignore);
}
} else {
if (actualJson == null && expectJson == null) {
ResultDetail resultDetail = new ResultDetail(prefix, "在actualJson中不存在", "在expectJson中不存在",
"Both Not Exist");
updateBaseResult(resultDetail);
} else if (actualJson == null) {
ResultDetail resultDetail = new ResultDetail(prefix, "在actualJson中不存在", expectJson, "Other Exist");
updateBaseResult(resultDetail);
} else{
ResultDetail resultDetail = new ResultDetail(prefix, actualJson, "在expectJson中不存在", "Not Exist");
updateBaseResult(resultDetail);
}
}
}
/** 非線性安全
* @Description: CompareFactory
* @Param: [parameter]
* @return: void
* @Author: YJiang
* @DateTimeFormat: 2020/3/8
*/
public staticBaseResult CompareFactory(T actual, T expect, String ignore) { /<string>/<resultdetail>/<resultdetail>/<code>
Compare.baseResult = new BaseResult();
Compare.compareJson(actual, expect, null,null, ignore);
return Compare.baseResult;
}
}
對了,之前寫過JSON 一致性比對的Python實現,有興趣的同學可以看一下哦 。
閱讀更多 軟件測試開發技術棧 的文章