JsonPathを使用してメンバーの数をカウントすることはできますか?
spring mvc test を使用して、生成するコントローラーをテストしています
{"foo": "oof", "bar": "rab"}
と
standaloneSetup(new FooController(fooService)).build()
.perform(get("/something").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.foo").value("oof"))
.andExpect(jsonPath("$.bar").value("rab"));
生成されたjsonに他のメンバーが存在しないことを確認したいと思います。できれば、jsonPathを使用してカウントしてください。出来ますか?代替ソリューションも歓迎します。
arrayのサイズをテストするには:jsonPath("$", hasSize(4))
objectのメンバーをカウントするには:jsonPath("$.*", hasSize(4))
つまりAPIが4つのアイテムのarrayを返すことをテストするには:
許容値:[1,2,3,4]
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$", hasSize(4)));
aPIが2つのメンバーを含むobjectを返すことをテストするには:
許容値:{"foo": "oof", "bar": "rab"}
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.*", hasSize(2)));
Hamcrestバージョン1.3とSpring Test 3.2.5.RELEASEを使用しています
注:hasSize()が機能するには、hamcrest-library依存関係とimport static org.hamcrest.Matchers.*;
を含める必要があります。
JsonPath functionssize()
またはlength()
のように使用できます。次のようになります。
@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);
}
または、単にnet.minidev.json.JSONObject
およびサイズを取得します。
@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);
}
実際、2番目のアプローチは最初のアプローチよりもパフォーマンスが良いようです。 JMHパフォーマンステストを行ったところ、次の結果が得られました。
| 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 |
サンプルコードは here にあります。
今日自分でこれを扱っています。これが利用可能なアサーションに実装されているようには見えません。ただし、org.hamcrest.Matcher
オブジェクトを渡すメソッドがあります。それにより、次のようなことができます。
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
}
})
Jsonpath内でメソッドを使用することもできます。そのため、
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.*", hasSize(2)));
できるよ
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.length()", is(2)));
クラスパスにcom.jayway.jsonassert.JsonAssert
がない場合(これは私の場合でした)、次の方法でテストすることで回避策が得られる可能性があります。
assertEquals(expectedLength, ((net.minidev.json.JSONArray)parsedContent.read("$")).size());
[注:jsonのコンテンツは常に配列であると仮定しました]