and*_*ras 70 testing maps table-driven go equivalence
我有一个像这样的表驱动测试用例:
func CountWords(s string) map[string]int
func TestCountWords(t *testing.T) {
  var tests = []struct {
    input string
    want map[string]int
  }{
    {"foo", map[string]int{"foo":1}},
    {"foo bar foo", map[string]int{"foo":2,"bar":1}},
  }
  for i, c := range tests {
    got := CountWords(c.input)
    // TODO test whether c.want == got
  }
}
我可以检查长度是否相同,并编写一个循环来检查每个键值对是否相同.但是当我想将它用于另一种类型的地图时(例如map[string]string),我必须再次编写此检查.
我最终做的是,我将地图转换为字符串并比较字符串:
func checkAsStrings(a,b interface{}) bool {
  return fmt.Sprintf("%v", a) != fmt.Sprintf("%v", b) 
}
//...
if checkAsStrings(got, c.want) {
  t.Errorf("Case #%v: Wanted: %v, got: %v", i, c.want, got)
}
这假设等效映射的字符串表示是相同的,在这种情况下似乎是正确的(如果键是相同的,那么它们散列到相同的值,因此它们的顺序将是相同的).有一个更好的方法吗?在表驱动测试中比较两个映射的惯用方法是什么?
jos*_*hlf 135
Go图书馆已经为您提供了保障.做这个:
import "reflect"
// m1 and m2 are the maps we want to compare
eq := reflect.DeepEqual(m1, m2)
if eq {
    fmt.Println("They're equal.")
} else {
    fmt.Println("They're unequal.")
}
如果你看一下源代码供reflect.DeepEqual的Map情况下,你会发现,如果它首先检查这两个地图是零,那么如果他们有相同的长度,最后检查,看看他们是否有相同的一组(键的前检查,价值)对.
因为reflect.DeepEqual采用接口类型,它将适用于任何有效的映射(map[string]bool, map[struct{}]interface{}等).请注意,它也适用于非地图值,因此请注意,传递给它的是两个地图.如果你传递两个整数,它会很高兴地告诉你它们是否相等.
eri*_*eda 12
使用 cmp ( https://github.com/google/go-cmp ) 代替:
if !cmp.Equal(src, expectedSearchSource) {
    t.Errorf("Wrong object received, got=%s", cmp.Diff(expectedSearchSource, src))
}
当预期输出中的映射“顺序”不是函数返回的值时,它仍然会失败。但cmp仍然能够指出不一致的地方。
作为参考,我找到了这条推文:
https://twitter.com/francesc/status/885630175668346880?lang=en
“在测试中使用 Reflect.DeepEqual 通常是一个坏主意,这就是我们开源http://github.com/google/go-cmp的原因” - Joe Tsai
zzz*_*zzz 10
这就是我要做的(未经测试的代码):
func eq(a, b map[string]int) bool {
        if len(a) != len(b) {
                return false
        }
        for k, v := range a {
                if w, ok := b[k]; !ok || v != w {
                        return false
                }
        }
        return true
}
Von*_*onC 10
在表驱动测试中比较两个映射的惯用方式是什么?
您有go-test/deep需要帮助的项目。
但是:这应该是使用更加简单围棋1.12(2019年2月)本机:请参见发行说明。
fmt现在可以按键排序的顺序打印地图,以简化测试。
排序规则是:
- 适用时,nil比较低
- 整数,浮点数和字符串排序依据
<- NaN比非NaN浮点数少
bool比较false之前true- 复杂比较真实,然后虚构
- 指针按机器地址比较
- 通道值按机器地址比较
- 结构依次比较每个字段
- 数组依次比较每个元素
- 接口值首先通过
reflect.Type描述具体类型进行比较,然后再按照先前规则中的具体值进行比较。打印地图时,非自反键值(如NaN)以前显示为。从此版本开始,将打印正确的值。
资料来源:
golang/go问题21095,purpleidea)CL添加:(CL代表“更改列表”)
为此,我们在根目录处
internal/fmtsort添加了一个包,该包实现了一种用于对映射键进行排序的通用机制,而不论其类型如何。这有点混乱,可能很慢,但是地图的格式化打印从未如此快速,并且始终是反射驱动的。
新软件包是内部的,因为我们确实不希望每个人都使用此软件包对事物进行排序。它很慢,不是通用的,并且仅适用于可以作为映射键的类型的子集。
还可以使用中的软件包text/template,该软件包已经具有较弱的机制。
您可以看到 src/fmt/print.go#
免责声明:map[string]int与在 Go 中测试地图的等效性无关但相关,这是问题的标题
如果您有地图指针类型的(像map[*string]int),那么你就不会想用reflect.DeepEqual因为它会返回false。
最后,如果key是一个包含未导出指针的类型,比如time.Time,那么reflect.DeepEqual在这样的映射上也可以返回false。
使用github.com/google/go-cmp/cmp的“Diff”方法:
代码:
// Let got be the hypothetical value obtained from some logic under test
// and want be the expected golden data.
got, want := MakeGatewayInfo()
if diff := cmp.Diff(want, got); diff != "" {
    t.Errorf("MakeGatewayInfo() mismatch (-want +got):\n%s", diff)
}
输出:
MakeGatewayInfo() mismatch (-want +got):
  cmp_test.Gateway{
    SSID:      "CoffeeShopWiFi",
-   IPAddress: s"192.168.0.2",
+   IPAddress: s"192.168.0.1",
    NetMask:   net.IPMask{0xff, 0xff, 0x00, 0x00},
    Clients: []cmp_test.Client{
        ... // 2 identical elements
        {Hostname: "macchiato", IPAddress: s"192.168.0.153", LastSeen: s"2009-11-10 23:39:43 +0000 UTC"},
        {Hostname: "espresso", IPAddress: s"192.168.0.121"},
        {
            Hostname:  "latte",
-           IPAddress: s"192.168.0.221",
+           IPAddress: s"192.168.0.219",
            LastSeen:  s"2009-11-10 23:00:23 +0000 UTC",
        },
+       {
+           Hostname:  "americano",
+           IPAddress: s"192.168.0.188",
+           LastSeen:  s"2009-11-10 23:03:05 +0000 UTC",
+       },
    },
  }
| 归档时间: | 
 | 
| 查看次数: | 44602 次 | 
| 最近记录: |