-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduces a type which can be used to mock calls #118
Conversation
This type is designed to easily and dynamically mock out calls to methods/functions so that tests can declare expected arguments and their return values without having to define custom functions for each test. In addition, calls and return-values are logged so that when tests fail it's easy to pinpoint why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really useful. It should make a lot of tests more concise, and easier to write and read.
One concern I have is matching more complex call arguments. For example, what if a function takes a pointer to some type which might not be accessible at mock setup time.
I guess you can always have special handling the fake type's method in these cases. I don't think this corner case should prevent you from landing this as it is now.
} | ||
|
||
func Example() { | ||
var logger loggo.Logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment here along the lines of:
// Set up mock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
mock.Call("Div", 1, 1).Returns(1, nil) | ||
mock.Call("Div", 1, 0).Returns(0, fmt.Errorf("cannot divide by zero")) | ||
|
||
example := ExampleTypeWhichUsesInterface{calculator: mock} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And another here:
// Use the mock to test ExampleTypeWhichUsesInterface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
m.timesInvoked.value++ | ||
} | ||
|
||
func (m *callMockReturner) numTimesInvoked() int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this seems useful, it's not exposed or used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's returned from Returns
so that you can check that functions are called. Example here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh... ignore me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very easy to miss!
// returned. It returns the results previously specified by the Call | ||
// function. If no results were specified, the returned slice will be | ||
// nil. | ||
func (m *CallMocker) MethodCall(receiver interface{}, fnName string, args ...interface{}) []interface{} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about naming this RecordCall? That would be closer to what it does.
type CallMocker struct { | ||
Stub | ||
|
||
logger loggo.Logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if this took a gc.C and used the Log method on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it would unnecessarily couple this type to gocheck. I wish gc.C satisified some kind of logger interface so that we could just pass it in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that would be better... Not coupling this to gc.C makes sense I guess, but the way it is ties this to loggo which isn't much better. Maybe at least make this a loggo style interface?
r.logCall() | ||
return r.retVals | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this should be an error, that is, shouldn't the test author be required to specify each possible call up front? Otherwise tests could end up passing unintentionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about panicing here; what happens in practice is that when people try to resolve an index on this result, they get a panic then indicating that they haven't specified a necessary call/result. Even if the function/method only returns one result, they'll have to do results[0].(int)
(or whatever), so there is no risk that tests will pass unintentionally.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with that.
m.timesInvoked.value++ | ||
} | ||
|
||
func (m *callMockReturner) numTimesInvoked() int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh... ignore me.
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju-testing |
This type is designed to easily and dynamically mock out calls to methods/functions so that tests can declare expected arguments and their return values without having to define custom functions for each test. In addition, calls and return-values are logged so that when tests fail it's easy to pinpoint why.