자식 순서를 무시하고 특히 웹 서비스에서 반환되는 JSON을 단위 테스트하는 두 JSON 객체 비교를 지원하는 JSON 구문 분석 라이브러리를 찾고 있습니다.
주요 JSON 라이브러리가 이것을 지원합니까? org.json 라이브러리는 단순히 참조 비교를 수행합니다.
자식 순서를 무시하고 특히 웹 서비스에서 반환되는 JSON을 단위 테스트하는 두 JSON 객체 비교를 지원하는 JSON 구문 분석 라이브러리를 찾고 있습니다.
주요 JSON 라이브러리가 이것을 지원합니까? org.json 라이브러리는 단순히 참조 비교를 수행합니다.
답변:
일반적인 아키텍처 포인트로서, 나는 보통 특정 직렬화 형식에 대한 의존성이 스토리지 / 네트워킹 계층을 넘어서 빠져 나가지 않도록 권고합니다. 따라서 먼저 JSON 표현이 아닌 자체 응용 프로그램 객체 간의 동등성을 테스트하는 것이 좋습니다.
나는 현재 Jackson 의 열렬한 팬이며 ObjectNode.equals () 구현 에 대한 빠른 읽기에서 원하는 멤버쉽 비교를 제안합니다.
public boolean equals(Object o)
{
if (o == this) return true;
if (o == null) return false;
if (o.getClass() != getClass()) {
return false;
}
ObjectNode other = (ObjectNode) o;
if (other.size() != size()) {
return false;
}
if (_children != null) {
for (Map.Entry<String, JsonNode> en : _children.entrySet()) {
String key = en.getKey();
JsonNode value = en.getValue();
JsonNode otherValue = other.get(key);
if (otherValue == null || !otherValue.equals(value)) {
return false;
}
}
}
return true;
}
Skyscreamer의 JSONAssert를 사용해보십시오 .
그것의 비 엄격 모드는 덜 취성 수 있도록 두 가지 장점이 있습니다 :
엄격 모드에서는 json-lib의 테스트 클래스와 비슷하게 동작합니다.
테스트는 다음과 같습니다.
@Test
public void testGetFriends() {
JSONObject data = getRESTData("/friends/367.json");
String expected = "{friends:[{id:123,name:\"Corby Page\"}"
+ ",{id:456,name:\"Solomon Duskis\"}]}";
JSONAssert.assertEquals(expected, data, false);
}
JSONAssert.assertEquals의 매개 변수 () 호출하는 expectedJSONString , actualDataString을 하고 isStrict .
결과 메시지는 매우 명확하며 실제로 큰 JSON 객체를 비교할 때 중요합니다.
JSONAssert.assertEquals(expected, data, JSONCompareMode.NON_EXTENSIBLE);
NON_EXTENSIBLE 모드는 새로운 필드 나 누락 된 필드가 실패를 일으키지 만 순서는 그렇지 않다는 것을 의미합니다. false를 사용하면 추가 또는 누락 된 하위 요소를보고하지 않는 관용 모드를 사용해야합니다.
GSON 사용
JsonParser parser = new JsonParser();
JsonElement o1 = parser.parse("{a : {a : 2}, b : 2}");
JsonElement o2 = parser.parse("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);
편집 : GSON v2.8.6 부터 인스턴스 메소드 JsonParser.parse
는 더 이상 사용되지 않습니다. 정적 메소드를 사용해야합니다 JsonParser.parseString
.
JsonElement o1 = JsonParser.parseString("{a : {a : 2}, b : 2}");
JsonElement o2 = JsonParser.parseString("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);
나는 다음을 할 것이다.
JSONObject obj1 = /*json*/;
JSONObject obj2 = /*json*/;
ObjectMapper mapper = new ObjectMapper();
JsonNode tree1 = mapper.readTree(obj1.toString());
JsonNode tree2 = mapper.readTree(obj2.toString());
return tree1.equals(tree2);
json-lib의 JSONAssert 클래스를 사용해보십시오 .
JSONAssert.assertEquals(
"{foo: 'bar', baz: 'qux'}",
JSONObject.fromObject("{foo: 'bar', baz: 'xyzzy'}")
);
제공합니다 :
junit.framework.ComparisonFailure: objects differed at key [baz]; expected:<[qux]> but was:<[xyzzy]>
JSONAssert.assertJsonEquals( "{foo: 'bar', list: [{test: '1'}, {rest: '2'}] }", "{ foo: 'bar', list: [{rest: '2'}, {test: '1'}] }");
메시지와 함께junit.framework.AssertionFailedError: : : objects differed at key [list];: arrays first differed at element [0];: objects differed at key [test];
이 라이브러리를 사용하십시오. https://github.com/lukas-krecan/JsonUnit
치어 리더 :
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit</artifactId>
<version>1.5.0</version>
<scope>test</scope>
</dependency>
IGNORING_ARRAY_ORDER-배열의 순서를 무시
assertJsonEquals("{\"test\":[1,2,3]}",
"{\"test\": [3,2,1]}",
when(IGNORING_ARRAY_ORDER)
);
JUnit을 이미 사용중인 경우 최신 버전은 Hamcrest를 사용합니다. 새로운 매칭기를 구축하기 위해 확장 될 수있는 일반적인 매칭 프레임 워크 (특히 단위 테스트에 유용함)입니다.
hamcrest-json
JSON을 인식 하는 작은 오픈 소스 라이브러리 가 있습니다. 문서화, 테스트 및 지원이 잘되어 있습니다. 다음은 유용한 링크입니다.
JSON 라이브러리의 객체를 사용하는 예제 코드 org.json.simple
:
Assert.assertThat(
jsonObject1.toJSONString(),
SameJSONAs.sameJSONAs(jsonObject2.toJSONString()));
선택적으로 (1) "모든 순서"배열을 허용하고 (2) 추가 필드를 무시할 수 있습니다.
Java 용 JSON 라이브러리의 다양한 있기 때문에 ( Jackson
, GSON
, json-lib
, 등)이 유용하다는 것을 hamcrest-json
지원하는 JSON 텍스트 (등 java.lang.String
), 더글러스 크록 포드의 JSON 라이브러리에서뿐만 아니라 기본적으로 지원하는 객체org.json
.
마지막으로 JUnit을 사용하지 않는 경우 어설 션에 Hamcrest를 직접 사용할 수 있습니다. ( 나는 여기에 썼습니다. )
내가 한 일이 놀라운 일 중 하나는 두 객체를 모두 HashMap으로 읽은 다음 일반 assertEquals ()와 비교하는 것입니다. 해시 맵의 equals () 메소드를 호출하여 내부의 모든 객체를 재귀 적으로 비교합니다 (다른 해시 맵 또는 문자열 또는 정수와 같은 단일 값 객체). 이것은 Codehaus의 Jackson JSON 파서를 사용하여 수행되었습니다.
assertEquals(mapper.readValue(expectedJson, new TypeReference<HashMap<String, Object>>(){}), mapper.readValue(actualJson, new TypeReference<HashMap<String, Object>>(){}));
JSON 객체가 대신 배열 인 경우 비슷한 방법을 사용할 수 있습니다.
나는 이것을 사용하고 있으며 나를 위해 잘 작동합니다 (org.json. * 사용).
package com.project1.helpers;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class JSONUtils {
public static boolean areEqual(Object ob1, Object ob2) throws JSONException {
Object obj1Converted = convertJsonElement(ob1);
Object obj2Converted = convertJsonElement(ob2);
return obj1Converted.equals(obj2Converted);
}
private static Object convertJsonElement(Object elem) throws JSONException {
if (elem instanceof JSONObject) {
JSONObject obj = (JSONObject) elem;
Iterator<String> keys = obj.keys();
Map<String, Object> jsonMap = new HashMap<>();
while (keys.hasNext()) {
String key = keys.next();
jsonMap.put(key, convertJsonElement(obj.get(key)));
}
return jsonMap;
} else if (elem instanceof JSONArray) {
JSONArray arr = (JSONArray) elem;
Set<Object> jsonSet = new HashSet<>();
for (int i = 0; i < arr.length(); i++) {
jsonSet.add(convertJsonElement(arr.get(i)));
}
return jsonSet;
} else {
return elem;
}
}
}
org.json의 경우 JSONObject 인스턴스와 비교할 수있는 자체 솔루션을 배포했습니다. 해당 프로젝트에서 복잡한 JSON 객체로 작업하지 않았으므로 모든 시나리오에서 이것이 작동하는지 알 수 없습니다. 또한 단위 테스트에서 이것을 사용한다고 가정하면 최적화에 노력을 기울이지 않았습니다. 여기있어:
public static boolean jsonObjsAreEqual (JSONObject js1, JSONObject js2) throws JSONException {
if (js1 == null || js2 == null) {
return (js1 == js2);
}
List<String> l1 = Arrays.asList(JSONObject.getNames(js1));
Collections.sort(l1);
List<String> l2 = Arrays.asList(JSONObject.getNames(js2));
Collections.sort(l2);
if (!l1.equals(l2)) {
return false;
}
for (String key : l1) {
Object val1 = js1.get(key);
Object val2 = js2.get(key);
if (val1 instanceof JSONObject) {
if (!(val2 instanceof JSONObject)) {
return false;
}
if (!jsonObjsAreEqual((JSONObject)val1, (JSONObject)val2)) {
return false;
}
}
if (val1 == null) {
if (val2 != null) {
return false;
}
} else if (!val1.equals(val2)) {
return false;
}
}
return true;
}
val1
if (!val1.equals(val2)) {
js2
입니다 null
여부를 때 js1
아니다null
RFC 6902 (JSON Patch)에 따라 diff 정보를 제공하는 zjsonpatch 라이브러리 를 사용할 수 있습니다 . 사용하기 매우 쉽습니다. 사용법에 대한 설명 페이지를 방문하십시오
http://json.org/java/ 에서 라이브러리를 가져 와서 equals
JSONObject 및 JSONArray 의 메소드를 수정하여 심도 평등 테스트를 수행하십시오. 아이들의 순서와 무관하게 작동하도록하려면 내부지도를으로 바꾸 TreeMap
거나 같은 것을 사용하면 Collections.sort()
됩니다.
이 시도:
public static boolean jsonsEqual(Object obj1, Object obj2) throws JSONException
{
if (!obj1.getClass().equals(obj2.getClass()))
{
return false;
}
if (obj1 instanceof JSONObject)
{
JSONObject jsonObj1 = (JSONObject) obj1;
JSONObject jsonObj2 = (JSONObject) obj2;
String[] names = JSONObject.getNames(jsonObj1);
String[] names2 = JSONObject.getNames(jsonObj1);
if (names.length != names2.length)
{
return false;
}
for (String fieldName:names)
{
Object obj1FieldValue = jsonObj1.get(fieldName);
Object obj2FieldValue = jsonObj2.get(fieldName);
if (!jsonsEqual(obj1FieldValue, obj2FieldValue))
{
return false;
}
}
}
else if (obj1 instanceof JSONArray)
{
JSONArray obj1Array = (JSONArray) obj1;
JSONArray obj2Array = (JSONArray) obj2;
if (obj1Array.length() != obj2Array.length())
{
return false;
}
for (int i = 0; i < obj1Array.length(); i++)
{
boolean matchFound = false;
for (int j = 0; j < obj2Array.length(); j++)
{
if (jsonsEqual(obj1Array.get(i), obj2Array.get(j)))
{
matchFound = true;
break;
}
}
if (!matchFound)
{
return false;
}
}
}
else
{
if (!obj1.equals(obj2))
{
return false;
}
}
return true;
}
if (obj1Array.length() != obj2Array.length())
보장 할 모든 요소가 일치?
나는 그것이 테스트를 위해서만 고려된다는 것을 알고 있지만 Hamcrest JSON에서 Hamcrest JSON 비교기 SameJSONA를 사용할 수 있습니다 .
JSON을 비교하려면 JSONCompare를 사용하는 것이 좋습니다. https://github.com/fslev/json-compare
// Compare by regex
String expected = "{\"a\":\".*me.*\"}";
String actual = "{\"a\":\"some text\"}";
JSONCompare.assertEquals(expected, actual); // True
// Check expected array has no extra elements
String expected = "[1,\"test\",4,\"!.*\"]";
String actual = "[4,1,\"test\"]";
JSONCompare.assertEquals(expected, actual); // True
// Check expected array has no numbers
String expected = "[\"\\\\\\d+\"]";
String actual = "[\"text\",\"test\"]";
JSONCompare.assertEquals(expected, actual); // True
// Check expected array has no numbers
String expected = "[\"\\\\\\d+\"]";
String actual = "[2018]";
JSONCompare.assertNotEquals(expected, actual); // True
Jackson과 함께 이것을하고 싶은 사람들에게는 json-unit을 사용할 수 있습니다 .
JsonAssert.assertJsonEquals(jsonNode1, jsonNode2);
이 오류는 불일치 유형에 대한 유용한 피드백을 제공합니다.
java.lang.AssertionError: JSON documents have different values:
Different value found in node "heading.content[0].tag[0]". Expected 10209, got 10206.
다른 것들은 제대로 작동하지 않는 것 같으므로 다음과 같이 썼습니다.
private boolean jsonEquals(JsonNode actualJson, JsonNode expectJson) {
if(actualJson.getNodeType() != expectJson.getNodeType()) return false;
switch(expectJson.getNodeType()) {
case NUMBER:
return actualJson.asDouble() == expectJson.asDouble();
case STRING:
case BOOLEAN:
return actualJson.asText().equals(expectJson.asText());
case OBJECT:
if(actualJson.size() != expectJson.size()) return false;
Iterator<String> fieldIterator = actualJson.fieldNames();
while(fieldIterator.hasNext()) {
String fieldName = fieldIterator.next();
if(!jsonEquals(actualJson.get(fieldName), expectJson.get(fieldName))) {
return false;
}
}
break;
case ARRAY:
if(actualJson.size() != expectJson.size()) return false;
List<JsonNode> remaining = new ArrayList<>();
expectJson.forEach(remaining::add);
// O(N^2)
for(int i=0; i < actualJson.size(); ++i) {
boolean oneEquals = false;
for(int j=0; j < remaining.size(); ++j) {
if(jsonEquals(actualJson.get(i), remaining.get(j))) {
oneEquals = true;
remaining.remove(j);
break;
}
}
if(!oneEquals) return false;
}
break;
default:
throw new IllegalStateException();
}
return true;
}
다음 코드는 두 JsonObject, JsonArray, JsonPrimitive 및 JasonElements를 비교하는 데 더 도움이됩니다.
private boolean compareJson(JsonElement json1, JsonElement json2) {
boolean isEqual = true;
// Check whether both jsonElement are not null
if (json1 != null && json2 != null) {
// Check whether both jsonElement are objects
if (json1.isJsonObject() && json2.isJsonObject()) {
Set<Entry<String, JsonElement>> ens1 = ((JsonObject) json1).entrySet();
Set<Entry<String, JsonElement>> ens2 = ((JsonObject) json2).entrySet();
JsonObject json2obj = (JsonObject) json2;
if (ens1 != null && ens2 != null) {
// (ens2.size() == ens1.size())
// Iterate JSON Elements with Key values
for (Entry<String, JsonElement> en : ens1) {
isEqual = isEqual && compareJson(en.getValue(), json2obj.get(en.getKey()));
}
} else {
return false;
}
}
// Check whether both jsonElement are arrays
else if (json1.isJsonArray() && json2.isJsonArray()) {
JsonArray jarr1 = json1.getAsJsonArray();
JsonArray jarr2 = json2.getAsJsonArray();
if (jarr1.size() != jarr2.size()) {
return false;
} else {
int i = 0;
// Iterate JSON Array to JSON Elements
for (JsonElement je : jarr1) {
isEqual = isEqual && compareJson(je, jarr2.get(i));
i++;
}
}
}
// Check whether both jsonElement are null
else if (json1.isJsonNull() && json2.isJsonNull()) {
return true;
}
// Check whether both jsonElement are primitives
else if (json1.isJsonPrimitive() && json2.isJsonPrimitive()) {
if (json1.equals(json2)) {
return true;
} else {
return false;
}
} else {
return false;
}
} else if (json1 == null && json2 == null) {
return true;
} else {
return false;
}
return isEqual;
}
JSON.areEqual(json1, json2); //using BlobCity Java Commons
https://tech.blobcity.com/2018/09/02/json-equals-in-java-to-compare-two-jsons
이 솔루션은 저에게 매우 좋습니다.
try {
// Getting The Array "Courses" from json1 & json2
Courses1 =json1.getJSONArray(TAG_COURSES1);
Courses2 = json2.getJSONArray(TAG_COURSES);
//LOOP FOR JSON1
for(int i = 0; i < Courses1.length(); i++){
//LOOP FOR JSON2
for(int ii = 0; ii < Courses2.length(); ii++){
JSONObject courses1 = Courses1.getJSONObject(i);
JSONObject courses2 = Courses2.getJSONObject(ii);
// Storing each json1 item in variable
int courseID1 = courses1.getInt(TAG_COURSEID1);
Log.e("COURSEID2:", Integer.toString(courseID1));
String Rating1 = courses1.getString(TAG_RATING1);
int Status1 = courses1.getInt(TAG_STATUS1);
Log.e("Status1:", Integer.toString(Status1)); //Put the actual value for Status1 in log.
// Storing each json2 item in variable
int courseID2 = courses2.getInt(TAG_COURSEID);
Log.e("COURSEID2:", Integer.toString(courseID)); //Put the actual value for CourseID in log
String Title2 = courses2.getString(TAG_TITLE);
String instructor2 = courses2.getString(TAG_INSTRUCTOR);
String length2 = courses2.getString(TAG_LENGTH);
String rating2 = courses2.getString(TAG_RATING);
String subject2 = courses2.getString(TAG_SUBJECT);
String description2 = courses2.getString(TAG_DESCRIPTION);
//Status1 = 5 from json1; Incomplete, Status1 =-1 Complete
if(Status1 == 5 && courseID2 == courseID1){
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
//Storing the elements if condition is true.
map.put(TAG_COURSEID, Integer.toString(courseID2)); //pend for compare
map.put(TAG_TITLE, Title2);
map.put(TAG_INSTRUCTOR, instructor2);
map.put(TAG_LENGTH, length2);
map.put(TAG_RATING, rating2);
map.put(TAG_SUBJECT, subject2); //show it
map.put(TAG_DESCRIPTION, description2);
//adding HashList to ArrayList
contactList.add(map);
}//if
}//for2 (json2)
} //for1 (json1)
}//Try
이것이 다른 사람들을 돕기를 바랍니다.
toString()
가 객체를JSON
문자열 로 변환하는 것을 지원 한다고 생각 합니다.