1. ホーム
  2. testing

[解決済み] Golangでマップの等価性をテストするには?

2022-10-30 08:54:49

質問

このようなテーブル駆動のテストケースがあります。

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)
}

これは等価なマップの文字列表現が同じであると仮定しており、この場合は正しいようです(キーが同じであれば同じ値にハッシュされるので、その命令は同じになります)。もっといい方法はないのでしょうか?テーブル駆動型テストにおいて2つのマップを比較する慣用的な方法は何ですか?

どのように解決するのですか?

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 's Map の場合、まず両方のマップが nil かどうかをチェックし、次に同じ長さかどうかをチェックし、最後に (key, value) ペアのセットが同じかどうかをチェックしていることがわかると思います。

なぜなら reflect.DeepEqual はインターフェース型を取るので、どんな有効なマップでも動作します ( map[string]bool, map[struct{}]interface{} など) に対して動作します。マップ以外の値でも動作するので、渡しているものが本当に2つのマップであるかどうか注意してください。もし2つの整数を渡せば、それが等しいかどうかを喜んで教えてくれるでしょう。