smarty / assertions

Fluent assertion-style functions used by goconvey and gunit. Can also be used in any test or application.
Other
100 stars 34 forks source link

New Assertion: ShouldEqualJSON (to compare two json strings) #25

Closed pschuegr closed 6 years ago

pschuegr commented 7 years ago

Would you accept a PR for a "ShouldEqualJSON" assertion? I find myself writing/using this assertion frequently...

mdwhatcott commented 7 years ago

Could you clarify a few things?

  1. Purpose of the assertion
  2. An example of intended usage
  3. How the assertion itself would work
pschuegr commented 7 years ago

Yup, I should have been a bit more verbose...

  1. To compare two strings of json which may be equivalent but are not exactly the same due to ordering, whitespace, etc.
actualJSON := `{"a":1, "b":2}`
expectedJSON := `{"b":2, "a":1}`
So(actualJSON, ShouldEqualJSON, expectedJSON)
  1. The way I've implemented this in my custom assertion is to take both strings, unmarshal them into map[string]interface{}, and then marshal them again and compare (marshalling of map keys happens in a specific order https://golang.org/src/encoding/json/encode.go#L138). If anything goes wrong during this process it fails.

Thoughts?

Edit: it occurs to me that arrays, strings, and numbers are also valid JSON, so there might be a better name for it (ShouldEqualJSONObject?). If you think this would be worth including then we could discuss.

mdwhatcott commented 7 years ago

Ah, now I see--comparing JSON strings regardless of key ordering. Thanks for the clarification.

Are your JSON strings coming from your own structs that were marshaled? (If so, you could compare the structs directly using ShouldResemble.) It almost feels like this is a variation on ShouldResemble...

mdwhatcott commented 7 years ago

I have a concern about depending on the current standard-library implementation of JSON key sorting. If that were to change down the road, the assertion could break. I'd recommend just doing a ShouldResemble on the map[string]interface{} values, but there have been issues reported regarding that kind of usage of ShouldResemble so I'm not sure if the suggestion is sound.

pschuegr commented 7 years ago

I'm actually using it more to compare strings directly, rather than structs that are already unmarshalled, so I think it's kind of a different use case? Maybe there's a better way to do this, but I'm using it to compare json responses from an api.

expectedRequestBody := `{"my":"json","format":"!"}`
c.So(body, ShouldEqualJSON, expectedRequestBody)

I can understand the concern with depending on the stlib sorting - but it would only break if they decided to enforce a non-stable sort or a random ordering on the marshalling. Which I suppose is a reasonable concern - ultimately your call. Feel free to close this issue if you think it's not worth it :)

Cheers

mdwhatcott commented 7 years ago

Ok, I'm starting to understand the use case. Is this a case where you don't ever plan to define a go struct into which you would unmarshal the data? Because if you did have such a struct definition it would be simple to unmarshal and compare with another (expected) instance of the same struct using ShouldResemble. That's the approach we've employed when needing to assert on data coming from a JSON source. Thoughts?

pschuegr commented 7 years ago

Sorry, was on vacation for a bit. I'll give this approach a try and report back if I still think this would provide value.

wedneyyuri commented 6 years ago

@mdwhatcott I'm testing a custom JSON Marshaler comparing the output against json files stored on disk.

Yes, I can do a ShouldResemble on the map[string]interface{}, but the diff will not look good.

mdwhatcott commented 6 years ago

@wedneyyuri - thanks for the feedback.

mdwhatcott commented 6 years ago

I'd welcome a pull request representing a draft of this assertion, including test cases that specify its basic behavior. Doesn't need to be production-grade just yet, more a proof-of-concept at this point. @pschuegr