Please add a method for JSONCompareMode.NON_EXTENSIBLE
to JsonExpectationsHelper
in spring-test
.
Because: mostly you want to assert that both requests contain exactly the same content and the same fields. But order of elements usually does not matter, as json is nothing other than a HashMap.
That's simply not possible to assert as of now.
NON_EXTENSIBLE
is the correct mode in that case.
Comment From: sbrannen
JsonExpectationsHelper
is primarily intended for use within the framework itself, and it is essentially just a wrapper around org.skyscreamer.jsonassert.JSONAssert
.
If you have been using JsonExpectationsHelper
directly in your code and want to make use of JSONCompareMode
, we would recommend that you instead use JSONAssert
.
Or... are you hoping to see more lenient matching in classes such as org.springframework.test.web.client.match.ContentRequestMatchers
, org.springframework.test.web.servlet.result.ContentResultMatchers
, and org.springframework.test.web.reactive.server.WebTestClient
?
Comment From: membersound
Ok indeed that would make sense to directly use JSONAssert
.
Still, if there is room for improved lenient json matching directly in the ContentMatchers, that would also be nice.
Comment From: sbrannen
Actually, we already have support for choosing between lenient and strict matching:
org.springframework.test.web.client.match.ContentRequestMatchers.json(String, boolean)
org.springframework.test.web.servlet.result.ContentResultMatchers.json(String, boolean)
If you supply true
for the above strict
flags, JSONCompareMode.STRICT
is used, but if you supply false
that switches to JSONCompareMode.LENIENT
.
Those delegate to JsonExpectationsHelper.assertJsonEqual(String, String, boolean)
which in turn delegates to org.skyscreamer.jsonassert.JSONAssert.assertEquals(String, String, boolean)
.
Please note as well that JsonExpectationsHelper.assertJsonEqual(String, String)
applies lenient matching by default, and that is used by DefaultWebTestClient.DefaultBodyContentSpec.json(String)
.
In light of that, I'm going to close this issue.
Comment From: membersound
If you supply
true
for the abovestrict
flags,JSONCompareMode.STRICT
is used, but if you supplyfalse
that switches toJSONCompareMode.LENIENT
.
Well but that's exactly the problem: LENIENT
will not detect of one of the comparable values contains additional elements. You mostly don't want that. STRICT
fixes this, but requires strict order of elements. Which for a json
hashmap is kind of useless, as json is per definition unsorted.
Thus, one should mostly use the NON_EXTENSIBLE
mode (which does not allow additional elements, but allows different order). And this mode is afaik not possible with ContentRequestMatchers
or ContentResultMatchers
.
Wouldn't it be worth extending the testclasses so that either JSONCompareMode
can be supplied as parameter, or add a NON_EXTENSIBLE
matcher method explicit?
To add some insight on a real world case: yesterday I discovered that some of my JUnit tests should have failed because in one of the json items, there was introduced a new field. But they did not, as by default the lenient mode explicit allows this behavior. And mostly this will be unintended, also for other users. I assume.
Comment From: sbrannen
Thus, one should mostly use the
NON_EXTENSIBLE
mode (which does not allow additional elements, but allows different order). And this mode is afaik not possible withContentRequestMatchers
orContentResultMatchers
.
That's correct.
Wouldn't it be worth extending the test classes so that either
JSONCompareMode
can be supplied as parameter,
We likely wouldn't want to introduce JSONCompareMode
as a parameter in order to avoid a direct dependency on JSONAssert in the API. JSONAssert is of course used under the hood as an implementation detail, but exposing that in the top-level APIs would prevent us from switching to a different implementation at a later date if desired.
or add a
NON_EXTENSIBLE
matcher method explicit?
That would be an option, though we'd likely have to introduce a method with a name other than json(...)
since we cannot introduce another json(String, boolean)
variant.
@rstoyanchev and @sdeleuze, thoughts?
Comment From: membersound
What about adding your own spring enum type that resembles to JSONCompareMode
? You're then free of api changes in future with json(String, SpringJsonCompareMode)
, but give the user the ability to directly chose the desired mode.
Some of them can then delegate to existing json(String, true)
and json(String, false)
, while another delegates explicit to the NON_EXTENSIBLE
?
Comment From: AviranBac
What about adding your own spring enum type that resembles to
JSONCompareMode
? You're then free of api changes in future withjson(String, SpringJsonCompareMode)
, but give the user the ability to directly chose the desired mode.Some of them can then delegate to existing
json(String, true)
andjson(String, false)
, while another delegates explicit to theNON_EXTENSIBLE
?
Hey, I strongly suggest this idea since I also found myself looking for a NON_EXTENSIBLE solution in your API but there isn't an implementation for it at the moment. I hope you can reconsider and reopen this issue.
Comment From: miriSch
@sbrannen is there a chance that the issue will be reopened? I could also use this.