【问题标题】:Matching JSON object with an instance将 JSON 对象与实例匹配
【发布时间】:2015-05-20 13:07:08
【问题描述】:

假设我有以下 DTO:

class C {
    String a;
    String b;
}

我有 JSON:

{
    "c" : {
        "a" : "aaa",
        "b" : "bbb"
    }
}

我想做的是,完成以下测试:

C expected = new C("aaa","bbb");
mockMvc.perform(get("url"))
    .andExpect(jsonPath("$.c", is(expected)));

失败了。如果我首先将expected 序列化为 JSON,然后尝试匹配,它会再次失败,因为它是一个字符串。这可能吗?

【问题讨论】:

  • 您的 JSON 无效。 = 应该是 :
  • 你可以看看jackson库
  • @Haketo 已修复,谢谢。

标签: java unit-testing jsonpath


【解决方案1】:

永远记住:没有“JSON 对象”这样的东西。 JSON 是对象的序列化格式。 JSON 始终是一个字符串。您可以从对象转换为 JSON 并返回(因此从对象转换为字符串并返回)。但是

{ "a": "b" }

是一个 JavaScript 对象,而不是 JSON(即使它看起来非常相似)。

这实际上是您问题的答案:当您序列化 expected 时,您会得到 JSON(传输格式,即字符串)。这不是jsonPath() 检查的内容。 jsonPath() 针对 JavaScript 类型进行验证。

This blog post 建议您需要单独检查每个字段:

.andExpect(jsonPath("$.c.a", is(expected.a)))
.andExpect(jsonPath("$.c.b", is(expected.b)));

这很乏味。你需要的是

a) 配置您的 JSON 框架以使用对键进行排序的映射系统和

b) 您需要弄清楚 jsonPath("$.c", ...) 返回的类型 - 它可能是您的 JSON 框架用来表示通用 JavaScript 对象的类型。

然后检查如下所示:

C c = new C("aaa","bbb");
String serialized = JSON.serialize(c); // to string
JSObject expected = JSON.parse(serialized); // to generic JavaScript object
mockMvc.perform(get("url"))
    .andExpect(jsonPath("$.c", is(expected)));

请注意,这仅在JSObjectequals() 具有正确实现时才有效。

【讨论】:

  • 这就是我要找的。我也是这么想的,只是找不到匹配的类。这太丑了。
  • 您使用哪个 JSON 框架?如果找不到,请在 is() 内设置一个断点,用于比较值。
  • 我的意思是直到你的回答我才知道 :) Jackson 将响应解析为 LinkedHashMap,因此按照你的建议,序列化和反序列化工作正常。
【解决方案2】:

如果您有能力修改“C”类以添加“等于”运算符并稍微修改您的 JSON 文件,我建议您将 JSON 字符串转换为“C”的实例。这可以通过一个好的 JSON-ifier(Jackson 或 GS​​ON)来完成。然后你只需要比较这两个实例。 GSON 的一些示例:

class C {
    String a;
    String b;
    public boolean equals(C obj) { return a.equals(obj.a) && b.equals(obj.b); }
}
// Your JSON file should look like that
{
    "a" : "aaa",
    "b" : "bbb"
}
// So the test is simple
C expected = new C("aaa","bbb");
C json = gson.fromJson(jsonString, C.class); 
if (expected.equals(json)) {
    // Do whatever you want here
}

如果您无法更改 JSON 文件,只需创建另一个类来包含您的主类,如下所示:

class Wrapper {
    C c;
}
Wrapper jsonW = gson.fromJson(jsonString, Wrapper.class);
C json = jsonW.c;
...

如果您无法承受添加等号运算符,我建议基于 2 个“C”实例对象创建 JSON 字符串并比较字符串。您的 jsonString 在结束为新字符串 (jsonStr) 之前成为真正的“C”对象 (json)。

String expectedStr = gson.toJson(expected);
String jsonStr = gson.toJSON(json);
if (expectedStr.equals(jsonStr)) {
    // Do whatever you want here
}

【讨论】:

  • 如果我不需要使用JsonPath,这将是正确的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
相关资源
最近更新 更多