How to test the equivalence of maps in Golang?

前端 未结 8 1338
情歌与酒
情歌与酒 2021-01-30 00:55

I have a table-driven test case like this one:

func CountWords(s string) map[string]int

func TestCountWords(t *testing.T) {
  var tests = []struct {
    input s         


        
相关标签:
8条回答
  • 2021-01-30 01:03

    Disclaimer: Unrelated to map[string]int but related to testing the equivalence of maps in Go, which is the title of the question

    If you have a map of a pointer type (like map[*string]int), then you do not want to use reflect.DeepEqual because it will return false.

    Finally, if the key is a type that contains an unexported pointer, like time.Time, then reflect.DeepEqual on such a map can also return false.

    0 讨论(0)
  • 2021-01-30 01:07

    This is what I would do (untested code):

    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
    }
    
    0 讨论(0)
  • 2021-01-30 01:12

    The Go library has already got you covered. Do this:

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

    If you look at the source code for reflect.DeepEqual's Map case, you'll see that it first checks if both maps are nil, then it checks if they have the same length before finally checking to see if they have the same set of (key, value) pairs.

    Because reflect.DeepEqual takes an interface type, it will work on any valid map (map[string]bool, map[struct{}]interface{}, etc). Note that it will also work on non-map values, so be careful that what you're passing to it are really two maps. If you pass it two integers, it will happily tell you whether they are equal.

    0 讨论(0)
  • 2021-01-30 01:13

    One of the options is to fix rng:

    rand.Reader = mathRand.New(mathRand.NewSource(0xDEADBEEF))
    
    0 讨论(0)
  • 2021-01-30 01:14

    What is the idiomatic way to compare two maps in table-driven tests?

    You have the project go-test/deep to help.

    But: this should be easier with Go 1.12 (February 2019) natively: See release notes.

    fmt.Sprint(map1) == fmt.Sprint(map2)
    

    fmt

    Maps are now printed in key-sorted order to ease testing.

    The ordering rules are:

    • When applicable, nil compares low
    • ints, floats, and strings order by <
    • NaN compares less than non-NaN floats
    • bool compares false before true
    • Complex compares real, then imaginary
    • Pointers compare by machine address
    • Channel values compare by machine address
    • Structs compare each field in turn
    • Arrays compare each element in turn
    • Interface values compare first by reflect.Type describing the concrete type and then by concrete value as described in the previous rules.

    When printing maps, non-reflexive key values like NaN were previously displayed as <nil>. As of this release, the correct values are printed.

    Sources:

    • golang/go issue 21095,
    • Tweet (original idea for that patch: ᴊᴀᴍᴇꜱ ᴊᴜꜱᴛ ᴊᴀᴍᴇꜱ (purpleidea)
    • CL 142737:

    The CL adds: (CL stands for "Change List")

    To do this, we add a package at the root, internal/fmtsort, that implements a general mechanism for sorting map keys regardless of their type.

    This is a little messy and probably slow, but formatted printing of maps has never been fast and is already always reflection-driven.

    The new package is internal because we really do not want everyone using this to sort things. It is slow, not general, and only suitable for the subset of types that can be map keys.

    Also use the package in text/template, which already had a weaker version of this mechanism.

    You can see that used in src/fmt/print.go#printValue(): case reflect.Map:

    0 讨论(0)
  • 2021-01-30 01:17

    Use the "Diff" method of github.com/google/go-cmp/cmp:

    Code:

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

    Output:

    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",
    +       },
        },
      }
    
    0 讨论(0)
提交回复
热议问题