MultiChecker for Unit Tests

The go module “github.com/juju/testing/checkers” has a new checker called MultiChecker which allows for more complex checking rules when comparing data structures.

It is common inside tests to want to compare a fairly deep data structure against an expected value, but sometimes these structures contain randomness (order of array elements, random IDs, functions etc). Normally a DeepEquals check would be sufficient, but in the event you want to ignore certain fields or treat a value different (such as using SameContents checker), MultiChecker allows you to do this based on path matching.

MultiChecker by default is a DeepEquals checker, but exceptions to the checker used can be specified by path.

Multiple path matching is available:

  • Add(path, checker, args…): takes the exact path to match
  • AddRegex(pathRegexString, checker, args…): takes a regexp expression to match the path
  • AddExpr(goExprString, checker, args…): takes a Golang expression. Underscore ident is used for wildcard matching. The root value must also be an underscore in Golang expressions.

When using a checker that requires the expected value (gc.Equals, jc.SameContents etc) pass in jc.ExpectedValue, this will be substituted for the value at the same path in the expected value.

Example

import jc "github.com/juju/testing/checkers"
import gc "gopkg.in/check.v1"
type User struct {
    Name string
    UUID string
    Friends []string
}
obtained := []User{
    User{"harry", "95231c26-b736-4bfa-a14c-9226bfca48f6", []string{"tim", "tom"}},
    User{"tom", "8e3ddb99-2f16-4e29-bd06-133199f748a6", []string{"tim", "harry"}},
    User{"tim", "f539db23-5d00-4c0c-9bd7-0d05b779e58d", []string{"harry", "tom"}},
}
expected := []User{
    User{"harry", "", []string{"tom", "tim"}},
    User{"tom", "", []string{"harry", "tim"}},
    User{"tim", "", []string{"tom", "harry"}},
}
checker := jc.NewMultiChecker().
    AddExpr("_[_].UUID", jc.Ignore).
    AddExpr("_[_].Friends", jc.SameContents, jc.ExpectedValue)
c.Assert(obtained, checker, expected)

Todo

  1. Custom array/slice index matching (matching indicies using a customizable sort function)
  2. Allow boolean checkers only on null expected maps, slices. (e.g. expected maps and slices need not be provided if the checker doesn’t require an expected value)
  3. Error on unused path matcher.
  4. Regex string matching inside subscript Go expression (e.g. _[Regex("harry-[0-9]+")].UUID )
  5. Numeric literal range matching inside subscript Go expression (e.g. _[Range(0, 10)].UUID )
  6. Add flag support to the checker, such as IgnoreUnexported, IgnoreUnmatched.
1 Like