Skip to content

Mock Matcher for functional options #997

@nbaztec

Description

@nbaztec

Hi,

In most go libraries nowadays (etcd, kubernets, aws, etc.) the functional options pattern is being used:

c := client.New(client.WithTimeout(), client.WithLabel("bar"))

The mocks for these functional options are unfortunately unable to match since the option usually is implemented so:

type opt struct {
  timeout bool
  label string
}

type ClientOption func(*opt)

func WithTimeout() ClientOption {
  return func(o *opt) {
    o.timeout = true
  }
}

func WithLabel(v string) ClientOption {
  return func(o *opt) {
    o.label = v
  }
}

func (c *client) New(opts ...ClientOption) *someClient {
  options := &opt{}
  for _, f := range opts {
    f(options)
  }

  return &someClient{options.timeout, options.label}
}

testify.Mock matcher will not match x := WithTimeout() with y := WithTimeout() since these are actually distinct functions. Using mock.AnythingOfType defeats the purpose since these options are usually significant and even critical to behavior.

As a workaround currently, I'm using reflection and the Call.Run() (alt. mock.MatchedBy) function to match these opts and log a proper diff (different options, different type, wrong values, etc.). I thought about it and it would've been ideal if we can introduce a matcher type mock.OptionTypeArgument or something since the MatchedBy func is inadequate for printing meaningful diffs as it will only true/false info of the failure scenario.

Is this something that the library could/should support? If yes, I can open a PR to elicit the approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions