The Jayway JsonPath library has support for reading values using a JSON path. If you would like to specifically use GSON or Jackson to do the deserialization (the default is to use json-smart), you can also configure this: Configuration.
JSONPath is a query language for JSON with features similar to XPath for XML. JSONPath is used for selecting and extracting a sub-section from the JSON document.
JsonPath expressions always refer to a JSON structure in the same way as XPath expression are used in combination with an XML document. The "root member object" in JsonPath is always referred to as $ regardless if it is an object or array. JsonPath expressions can use the dot–notation.
JSONPath is a query language for JSON, similar to XPath for XML. XPath expression can be used to extract information from an XML document by evaluating given expression.
To test size of array: jsonPath("$", hasSize(4))
To count members of object: jsonPath("$.*", hasSize(4))
I.e. to test that API returns an array of 4 items:
accepted value: [1,2,3,4]
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$", hasSize(4)));
to test that API returns an object containing 2 members:
accepted value: {"foo": "oof", "bar": "rab"}
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.*", hasSize(2)));
I'm using Hamcrest version 1.3 and Spring Test 3.2.5.RELEASE
hasSize(int) javadoc
Note:
You need to include hamcrest-library dependency and import static org.hamcrest.Matchers.*;
for hasSize() to work.
You can also use the methods inside the jsonpath, so instead of
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.*", hasSize(2)));
you can do
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.length()", is(2)));
We can use JsonPath functions like size()
or length()
, like this:
@Test
public void givenJson_whenGetLengthWithJsonPath_thenGetLength() {
String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";
int length = JsonPath
.parse(jsonString)
.read("$.length()");
assertThat(length).isEqualTo(3);
}
Or simply parsing to net.minidev.json.JSONObject
and get the size:
@Test
public void givenJson_whenParseObject_thenGetSize() {
String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";
JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonString);
assertThat(jsonObject)
.size()
.isEqualTo(3);
}
Indeed, the second approach looks to perform better than the first one. I made a JMH performance test and I get the following results:
| Benchmark | Mode | Cnt | Score | Error | Units |
|-------------------------------------------------|-------|-----|-------------|--------------|-------|
| JsonPathBenchmark.benchmarkJSONObjectParse | thrpt | 5 | 3241471.044 | ±1718855.506 | ops/s |
| JsonPathBenchmark.benchmarkJsonPathObjectLength | thrpt | 5 | 1680492.243 | ±132492.697 | ops/s |
The example code can be found here.
Been dealing with this myself today. It doesn't seem like this is implemented in the available assertions. However, there is a method to pass in an org.hamcrest.Matcher
object. With that you can do something like the following:
final int count = 4; // expected count
jsonPath("$").value(new BaseMatcher() {
@Override
public boolean matches(Object obj) {
return obj instanceof JSONObject && ((JSONObject) obj).size() == count;
}
@Override
public void describeTo(Description description) {
// nothing for now
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With