如何比较两个JSON请求?

如何比较两个JSON请求?,json,go,Json,Go,短篇故事:如何比较两块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) re

短篇故事:如何比较两块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
}
长话短说: 我正在做一些E2E测试,其中一部分我需要将请求的JSON正文与接收到的JSON进行比较。为此,我尝试将预期和接收到的json解组到一个空接口(以避免任何类型错误),但我得到一个错误:
json:Unmarshal(nil)
。我猜encoding/json不喜欢空接口,所以问题是如何比较两块json?字符串比较很容易出错,所以我尽量避免这种情况。

您需要传递指向
解码
解组
的指针。我用
func-JSONEqual(a,b io.Reader)
JSONBytesEqual(a,b[]字节)
,两者都返回
(bool,error)
。通过使用
bytes.NewBuffer
strings.NewReader>包装预期内容,可以将请求正文与静态预期内容进行比较(就像您在问题中尝试做的那样)。代码如下:

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)
}
它输出:

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
a=b为真,有错误
a=c为假,有误
a=空false,错误为EOF
a=错误为false,错误为无效字符“t”,查找对象键字符串的开头

我编写了一个用于比较基于http json的响应的工具,这样做忽略了顺序。您可以查看实现比较的包并获取相等函数:

例如:

b1:=[]字节(`{“x”:{“t”:1,“s”:2},“z”:1}`)
b2:=[]字节(`z:1,x:{s:2,t:1}`)
j1,:=解组(b1)
j2,:=解组(b2)
assert.True(t,等于(j1,j2))

来这里参加聚会太晚了

golang中有一个流行的测试包,名为require
github.com/stretchr/authentic/require
,它可以为您完成这项工作

func TestJsonEquality(t *testing.t) { 
  expected := `{"a": 1, "b": 2} `
  actual := ` {"b":   2, "a":   1}`
  require.JSONEq(t, expected, actual)
}

GoDocs:

我认为您只需要将声明更改为
j,j2:=map[string]接口{}{}{},map[string]接口{}{}
。我知道你想要一个完整的例子,以便最好地给出一个好的答案不,我最初的评论是错误的;你需要将指针传递到
Decode
/
Unmarshal
(虽然完整的示例仍然有用!)。我读到没有指向接口的指针的意义,因为接口{}已经是一种指针了。这有什么不同?好问题,如果你在StackOverflow上读到这可能是我的错,也许我应该修改一下答案,呵呵。接口,像切片值一样,实际上是包含指针的小结构。但是在这里,我们实际上想让
Unmarshal
改变这个小结构中的内容(从
nil
map[struct]接口{}
它必须分配),所以我们必须给它一个指向它的指针。可能还有更多的内容,但当您试图避免复制时,接口值就像指针:如果它引用了一大块数据,复制接口值将不会复制指向的数据。例如,不分配1000字节。当指向的东西被修改时,你仍然需要使用指针——这就是为什么你需要在这里使用指针的原因。(我刚刚在顶部的部分添加了一些细节,试图避免让未来的读者对此感到困惑。)太好了!谢谢你的回答!