go-cmpでmap内の時間文字列を近似比較する
以下のような関数をテストする際、期待する値もtime.Now()
で生成して概ね問題ない。
func f() map[string]interface{} { return map[string]interface{}{ "time": time.Now().Format("2006-01-02 15:04:05"), } }
ただし関数内に多くの処理がある場合など、ごく稀に時間がズレてFAILしてしまうことがある。
こういった関数を作らないことで回避することもできるが、cmp.FilterPathを使うと次のような比較処理を実装できる。
- mapの特定のキーに対して、
- 値を
interface{}
からtime.Time
に変換し、 - 2つの値の差が1秒以下ならOKとする
cmp.FilterPath(func(p cmp.Path) bool { if mi, ok := p.Index(-1).(cmp.MapIndex); ok { // 1. mapのキーがtimeの場合はComparerを使う return mi.Key().String() == "time" } return false }, cmp.Comparer(func(x, y interface{}) bool { // 2. time.Timeに変換する xt, ok := parseTime(x) if !ok { return false } yt, ok := parseTime(y) if !ok { return false } if xt.Before(yt) { // xt.Sub(yt)が負の値にならないように入れ替える xt, yt = yt, xt } // 3. Durationが1秒以下ならOKとする return xt.Sub(yt) <= time.Second }))