将JSON对象与实例匹配

时间:2015-05-20 13:07:09

标签: java unit-testing jsonpath

假设我有以下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然后尝试匹配,则它会再次失败,因为它是一个字符串。这可能吗?

2 个答案:

答案 0 :(得分:2)

永远记住:没有“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)));

请注意,仅当JSObject具有equals()的正确实现时才有效。

答案 1 :(得分:1)

如果你有能力修改你的" C"将它添加到"等于"运算符和稍微修改你的JSON文件,我建议你将你的JSON字符串转换为" C"的实例。这可以通过一个好的JSON-ifier(Jackson或GSON)来完成。然后你只需要比较2个实例。 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;
...

如果你买不起equals运算符,我建议根据2" C"创建JSON字符串。实例对象并比较字符串。你的jsonString成为一个真实的" C"在结束新字符串(jsonStr)之前的对象(json)。

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