英文:
How to compare two JSON requests?
问题
短故事:我该如何比较两个 JSON 块?下面的代码报错了。
var j, j2 interface{}
b := []byte(srv.req)
if err := json.Unmarshal(b, j); err != nil {
t.Errorf("err %v, req %s", err, b)
return
}
d := json.NewDecoder(r.Body)
if err := d.Decode(j2); err != nil {
t.Error(err)
return
}
if !reflect.DeepEqual(j2, j) {
t.Errorf("j %v, j2 %v", j, j2)
return
}
长故事:
我正在进行一些端到端的测试,其中一部分是需要将请求的 JSON 主体与接收到的 JSON 进行比较。为了做到这一点,我尝试将预期的和接收到的 JSON 解组为一个空接口(以避免任何类型错误),但是我遇到了一个错误:json: Unmarshal(nil)
。我猜测 encoding/json 不喜欢空接口,所以问题是我该如何比较两个 JSON 块?字符串比较容易出错,所以我想避免使用字符串比较。
英文:
Short Story: How can I compare two chunks of JSON? The code below errors out.
var j, j2 interface{}
b := []byte(srv.req)
if err := json.Unmarshal(b, j); err !=nil{
t.Errorf("err %v, req %s", err, b)
return
}
d := json.NewDecoder(r.Body)
if err := d.Decode(j2); err !=nil{
t.Error(err)
return
}
if !reflect.DeepEqual(j2, j){
t.Errorf("j %v, j2 %v", j, j2)
return
}
Long Story:
I'm doing some E2E testings and part of this I need to compare the requested JSON body with the received JSON. To do this I've tried to unmarshal the expected and received json to an empty interface (to avoid any type mistakes) but I get an error:
json: Unmarshal(nil)
. I guess encoding/json doesn't like the empty interface so the question is how can I compare two chunks of JSON? A string comparison would be error prone so I'm trying to avoid that.
答案1
得分: 38
你好!以下是翻译好的内容:
非常晚才来参加派对。
在golang中有一个受欢迎的测试包,叫做require github.com/stretchr/testify/require
,它可以为你完成这个任务。
func TestJsonEquality(t *testing.T) {
expected := `{"a": 1, "b": 2} `
actual := ` {"b": 2, "a": 1}`
require.JSONEq(t, expected, actual)
}
GoDocs文档:https://godoc.org/github.com/stretchr/testify/require#JSONEqf
英文:
Super late to the party here.
There is a popular testing package in golang called require github.com/stretchr/testify/require
and it will do this for you.
func TestJsonEquality(t *testing.t) {
expected := `{"a": 1, "b": 2} `
actual := ` {"b": 2, "a": 1}`
require.JSONEq(t, expected, actual)
}
GoDocs: https://godoc.org/github.com/stretchr/testify/require#JSONEqf
答案2
得分: 17
你需要将指针传递给Decode
和Unmarshal
函数。我在这里提供了一个可运行的示例,其中包含func JSONEqual(a, b io.Reader)
和JSONBytesEqual(a, b []byte)
两个函数,它们都返回(bool, error)
。你可以通过使用bytes.NewBuffer
或strings.NewReader
来将请求体与静态的预期内容进行比较(就像你在问题中尝试的那样)。以下是代码示例:
package main
import (
"encoding/json"
"fmt"
"io"
"reflect"
)
// JSONEqual比较两个Reader中的JSON。
func JSONEqual(a, b io.Reader) (bool, error) {
var j, j2 interface{}
d := json.NewDecoder(a)
if err := d.Decode(&j); err != nil {
return false, err
}
d = json.NewDecoder(b)
if err := d.Decode(&j2); err != nil {
return false, err
}
return reflect.DeepEqual(j2, j), nil
}
// JSONBytesEqual比较两个字节切片中的JSON。
func JSONBytesEqual(a, b []byte) (bool, error) {
var j, j2 interface{}
if err := json.Unmarshal(a, &j); err != nil {
return false, err
}
if err := json.Unmarshal(b, &j2); err != nil {
return false, err
}
return reflect.DeepEqual(j2, j), nil
}
func main() {
a := []byte(`{"x": ["y",42]}`)
b := []byte(`{"x": ["y", 42]}`)
c := []byte(`{"z": ["y", "42"]}`)
empty := []byte{}
bad := []byte(`{this? this is a test.}`)
eq, err := JSONBytesEqual(a, b)
fmt.Println("a=b\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, c)
fmt.Println("a=c\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, empty)
fmt.Println("a=empty\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, bad)
fmt.Println("a=bad\t", eq, "with error", err)
}
它的输出结果为:
a=b true with error <nil>
a=c false with error <nil>
a=empty false with error EOF
a=bad false with error invalid character 't' looking for beginning of object key string
英文:
You need to pass pointers to Decode
and Unmarshal
. I put up a runnable sample with func JSONEqual(a, b io.Reader)
and JSONBytesEqual(a, b []byte)
, both returning (bool, error)
. You can compare a request body to your static expected content (like you're trying to do in the question) by wrapping your expected content using bytes.NewBuffer
or strings.NewReader
. Here's the code:
package main
import (
"encoding/json"
"fmt"
"io"
"reflect"
)
// JSONEqual compares the JSON from two Readers.
func JSONEqual(a, b io.Reader) (bool, error) {
var j, j2 interface{}
d := json.NewDecoder(a)
if err := d.Decode(&j); err != nil {
return false, err
}
d = json.NewDecoder(b)
if err := d.Decode(&j2); err != nil {
return false, err
}
return reflect.DeepEqual(j2, j), nil
}
// JSONBytesEqual compares the JSON in two byte slices.
func JSONBytesEqual(a, b []byte) (bool, error) {
var j, j2 interface{}
if err := json.Unmarshal(a, &j); err != nil {
return false, err
}
if err := json.Unmarshal(b, &j2); err != nil {
return false, err
}
return reflect.DeepEqual(j2, j), nil
}
func main() {
a := []byte(`{"x": ["y",42]}`)
b := []byte(`{"x": ["y", 42]}`)
c := []byte(`{"z": ["y", "42"]}`)
empty := []byte{}
bad := []byte(`{this? this is a test.}`)
eq, err := JSONBytesEqual(a, b)
fmt.Println("a=b\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, c)
fmt.Println("a=c\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, empty)
fmt.Println("a=empty\t", eq, "with error", err)
eq, err = JSONBytesEqual(a, bad)
fmt.Println("a=bad\t", eq, "with error", err)
}
It outputs:
a=b true with error <nil>
a=c false with error <nil>
a=empty false with error EOF
a=bad false with error invalid character 't' looking for beginning of object key string
答案3
得分: 4
我为比较基于HTTP的JSON响应编写了一个工具,而且在比较时忽略了顺序。你可以查看实现比较并获取Equal函数的包:
https://github.com/emacampolo/gomparator/blob/master/json_util.go#L10
例如:
b1 := []byte(`{"x": {"t": 1, "s": 2}, "z": 1}`)
b2 := []byte(`{"z": 1, "x": {"s": 2, "t": 1}}`)
j1, _ := Unmarshal(b1)
j2, _ := Unmarshal(b2)
assert.True(t, Equal(j1, j2))
英文:
I wrote a tool for comparing http json-based responses and I do so ignoring order. You can take a look at the package that implements the comparison and grab the Equal function:
https://github.com/emacampolo/gomparator/blob/master/json_util.go#L10
eg:
b1 := []byte(`{"x": {"t": 1, "s": 2}, "z": 1}`)
b2 := []byte(`{"z": 1, "x": {"s": 2, "t": 1}}`)
j1, _ := Unmarshal(b1)
j2, _ := Unmarshal(b2)
assert.True(t, Equal(j1, j2))
答案4
得分: 0
考虑使用位于https://pkg.go.dev/github.com/wI2L/jsondiff的包,该包可以帮助计算两个JSON文档之间的差异,以一系列RFC6902(JSON Patch)操作的形式呈现。以下是文档中的一个示例:
import "github.com/wI2L/jsondiff"
patch, err := jsondiff.Compare(pod, newPod)
if err != nil {
// 处理错误
}
b, err := json.MarshalIndent(patch, "", " ")
if err != nil {
// 处理错误
}
os.Stdout.Write(b)
这段代码使用jsondiff.Compare
函数比较pod
和newPod
两个JSON文档,并返回一个表示差异的patch
对象。然后,使用json.MarshalIndent
函数将patch
对象转换为格式化的JSON字符串,并将其写入标准输出。
英文:
Consider using the package at https://pkg.go.dev/github.com/wI2L/jsondiff that helps computing the diff between two JSON documents as a series of RFC6902 (JSON Patch) operations. An example form the docs:
import "github.com/wI2L/jsondiff"
patch, err := jsondiff.Compare(pod, newPod)
if err != nil {
// handle error
}
b, err := json.MarshalIndent(patch, "", " ")
if err != nil {
// handle error
}
os.Stdout.Write(b)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论