将 JSON 个对象与实例匹配
Matching JSON object with an instance
假设我有以下 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 然后尝试匹配,它再次失败,因为它是一个字符串。这可能吗?
如果您有能力修改您的 "C" class 以添加一个 "equals" 运算符并稍微修改您的 JSON 文件,我建议您转换您的 JSON 字符串转换为 "C" 的实例。这可以通过一个好的 JSON-ifier(Jackson 或 GSON)来完成。然后你只需要比较这两个实例。
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 来包含您的主要 class,如下所示:
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
}
永远记住:没有“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", ...)
returns - 它可能是你的 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)));
请注意,这仅在 JSObject
具有 equals()
的正确实施时才有效。
假设我有以下 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 然后尝试匹配,它再次失败,因为它是一个字符串。这可能吗?
如果您有能力修改您的 "C" class 以添加一个 "equals" 运算符并稍微修改您的 JSON 文件,我建议您转换您的 JSON 字符串转换为 "C" 的实例。这可以通过一个好的 JSON-ifier(Jackson 或 GSON)来完成。然后你只需要比较这两个实例。 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 来包含您的主要 class,如下所示:
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
}
永远记住:没有“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", ...)
returns - 它可能是你的 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)));
请注意,这仅在 JSObject
具有 equals()
的正确实施时才有效。