知識庫 / Testing RSS 訂閱

忽略順序,檢索JSON對象集合

JSON,Testing
HongKong
5
09:42 PM · Dec 05 ,2025

1. 介紹

確定 JSON 對象集合的相等性可能具有挑戰性,尤其當集合中元素的順序無法保證時。雖然像 Jackson 和 AssertJ 這樣的庫可以被使用,但像 JSONassert 和 hamcrest-json 這樣更專業的工具旨在更可靠地處理這種情況。

在本教程中,我們將探索如何比較 JSON 對象集合,重點是忽略元素順序,使用 JSONassert 和 hamcrest-json

2. 問題陳述

當處理 JSON 對象集合時,列表中元素的順序會因數據源而異。

請考慮以下 JSON 數組:

[
  {"id": 1, "name": "Alice", "address": {"city": "NY", "street": "5th Ave"}},
  {"id": 2, "name": "Bob", "address": {"city": "LA", "street": "Sunset Blvd"}}
]
[
  {"id": 2, "name": "Bob", "address": {"city": "LA", "street": "Sunset Blvd"}},
  {"id": 1, "name": "Alice", "address": {"city": "NY", "street": "5th Ave"}}
]

雖然這些數組包含相同元素,但順序不同。直接字符串比較這些數組會因為順序差異而失敗,儘管它們的數據完全相同

讓我們將這些JSON數組定義為Java變量,然後探索如何比較它們以忽略順序:

String jsonArray1 = "["
        + "{\"id\": 1, \"name\": \"Alice\", \"address\": {\"city\": \"NY\", \"street\": \"5th Ave\"}}, "
        + "{\"id\": 2, \"name\": \"Bob\", \"address\": {\"city\": \"LA\", \"street\": \"Sunset Blvd\"}}"
        + "]";

String jsonArray2 = "["
        + "{\"id\": 2, \"name\": \"Bob\", \"address\": {\"city\": \"LA\", \"street\": \"Sunset Blvd\"}}, "
        + "{\"id\": 1, \"name\": \"Alice\", \"address\": {\"city\": \"NY\", \"street\": \"5th Ave\"}}"
        + "]";

3. 使用 JSONassert 進行 JSON 比較

JSONassert 提供了一種靈活的方式來比較 JSON 數據,允許我們比較 JSON 對象或數組,而不是直接進行字符串比較。 尤其,它能夠比較數組,同時忽略元素順序。

使用 LENIENT 模式,JSONAssert 僅關注內容,忽略順序:

@Test
public void givenJsonArrays_whenUsingJSONAssertIgnoringOrder_thenEqual() throws JSONException {
    JSONAssert.assertEquals(jsonArray1, jsonArray2, JSONCompareMode.LENIENT);
}

在本測試中,JSONCompareMode.LENIENT 模式允許我們斷言相等性,同時忽略元素順序。 這使得 JSONassert 適用於我們期望數據相同,但元素順序可能不同的情況

3.1. 忽略多餘字段,使用 JSONassert

JSONassert 同樣允許忽略 JSON 對象中的多餘字段,通過使用 LENIENT 模式實現。 這在比較 JSON 數據時非常有用,例如某些字段(如元數據或時間戳)與測試無關時

@Test
public void givenJsonWithExtraFields_whenIgnoringExtraFields_thenEqual() throws JSONException {
    String jsonWithExtraFields = "["
            + "{\"id\": 1, \"name\": \"Alice\", \"address\": {\"city\": \"NY\", \"street\": \"5th Ave\"}, \"age\": 30}, "
            + "{\"id\": 2, \"name\": \"Bob\", \"address\": {\"city\": \"LA\", \"street\": \"Sunset Blvd\"}, \"age\": 25}"
            + "]";

    JSONAssert.assertEquals(jsonArray1, jsonWithExtraFields, JSONCompareMode.LENIENT);
}

在本示例中,測試驗證 jsonArray1jsonWithExtraFields 的等效性,允許在比較中包含額外的字段,例如 age

4. 使用 hamcrest-json 進行 JSON 匹配

除了 JSONassert,我們還可以利用 hamcrest-json,這是一個專門為 Hamcrest 設計的 JSON 斷言插件。該插件基於 Hamcrest 的匹配器功能,允許我們在 JUnit 中編寫表達豐富且易讀的 JSON 斷言。

hamcrest-json 最有用的功能之一是 allowingAnyArrayOrdering() 方法。它允許我們比較 JSON 數組時忽略它們的順序:

@Test
public void givenJsonCollection_whenIgnoringOrder_thenEqual() {
    assertThat(jsonArray1, sameJSONAs(jsonArray2).allowingAnyArrayOrdering());
}

這種方法確保 JSON 比較忽略數組中元素的順序,使用 sameJSONAs() 匹配器。

4.1. 忽略額外字段,使用 hamcrest-json

除了忽略數組順序之外,hamcrest-json 還提供了 allowingExtraUnexpectedFields() 實用方法,用於處理額外的字段。 此方法允許我們忽略在一種 JSON 對象中存在,但在另一種 JSON 對象中不存在的字段:

@Test
public void givenJsonWithUnexpectedFields_whenIgnoringUnexpectedFields_thenEqual() {
    String jsonWithUnexpectedFields = "["
            + "{\"id\": 1, \"name\": \"Alice\", \"address\": {\"city\": \"NY\", \"street\": \"5th Ave\"}, \"extraField\": \"ignoreMe\"}, "
            + "{\"id\": 2, \"name\": \"Bob\", \"address\": {\"city\": \"LA\", \"street\": \"Sunset Blvd\"}}"
            + "]";

    assertThat(jsonWithUnexpectedFields, sameJSONAs(jsonArray1).allowingExtraUnexpectedFields());
}

在本示例中,我們驗證 jsonWithUnexpectedFields 等於 jsonArray1,即使它包含一個額外的字段。通過結合使用 allowingExtraUnexpectedFields()allowingAnyArrayOrdering(),我們確保進行一種健壯的比較,該比較專注於匹配我們 JSON 數組之間的數據。

5. 結論

在本文中,我們展示瞭如何通過使用專門的庫(如JSONassert和hamcrest-json)比較 JSON 對象集合,同時忽略元素順序的方法。與手動解析 JSON 到 Java 對象相比,這些庫提供了一種更直接、更可靠、更易於使用的方案。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.