Matching a JSON object with an instance
Suppose I have a DTO:
class C {
String a;
String b;
}
And I have JSON:
{
"c" : {
"a" : "aaa",
"b" : "bbb"
}
}
What I want to do is do the following test:
C expected = new C("aaa","bbb");
mockMvc.perform(get("url"))
.andExpect(jsonPath("$.c", is(expected)));
He fails. If I serialize expected
to JSON first and then try to match it fails again because it is a string. Is it possible?
source to share
Always remember: there is no such thing as a "JSON object". JSON is a serialization format for objects. JSON is always a string. You can convert from object to JSON and back (and therefore from object to string and back). But
{ "a": "b" }
- a JavaScript object, not JSON (even if it looks very similar).
This is actually the answer to your question: when you serialize expected
, you get JSON (transport format, i.e. string). This is not what tests jsonPath()
. jsonPath()
checks JavaScript types.
This blog post suggests that you need to validate each field separately:
.andExpect(jsonPath("$.c.a", is(expected.a)))
.andExpect(jsonPath("$.c.b", is(expected.b)));
which is tedious. What you need is a) set up your JSON structure to use a mapping system that sorts the keys, and b) you need to figure out what type it jsonPath("$.c", ...)
returns - this is probably the type your JSON framework uses to represent common JavaScript objects.
Then the check looks like this:
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)));
Note that this only works if it JSObject
has the correct implementation for equals()
.
source to share
If you can afford to modify your "C" class to add it to the "equals" and modify your JSON file a bit, I would suggest you convert your JSON string to an instance of "C". This can be done with a good JSON-ifier (Jackson or GSON). Then you just need to compare two instances. Some examples with 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
}
If you can't afford to change the JSON file, just create another class that will contain your main class, for example:
class Wrapper {
C c;
}
Wrapper jsonW = gson.fromJson(jsonString, Wrapper.class);
C json = jsonW.c;
...
If you cannot afford adding equals statement, I suggest creating a JSON string based on instance 2 "C" instances and comparing the strings. Your jsonString becomes a real "C" object (json) and then ends with a new string (jsonStr).
String expectedStr = gson.toJson(expected);
String jsonStr = gson.toJSON(json);
if (expectedStr.equals(jsonStr)) {
// Do whatever you want here
}
source to share