【发布时间】:2013-08-13 11:52:19
【问题描述】:
我有一个像这样的表驱动测试用例:
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)
}
这假设等效映射的字符串表示是相同的,在这种情况下似乎是正确的(如果键相同,则它们散列到相同的值,因此它们的顺序将相同)。有一个更好的方法吗?在表驱动测试中比较两个地图的惯用方法是什么?
【问题讨论】:
-
Err, no: 不保证迭代 map 的顺序是predictable: "map 上的迭代顺序没有指定,不保证从一次迭代到下一个……”.
-
此外,对于某些尺寸的地图,Go 会故意随机化顺序。强烈建议不要依赖该顺序。
-
尝试比较地图是您程序中的设计缺陷。
-
请注意,在 go 1.12(2019 年 2 月)中,地图现在按键排序顺序打印以简化测试。见my answer below
标签: testing maps go equivalence table-driven