-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
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.