Skip to content
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

Merged
merged 2 commits into from
Nov 24, 2016

Conversation

kat-co
Copy link
Contributor

@kat-co kat-co commented Nov 23, 2016

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.

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.
Copy link

@mjs mjs left a 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
Copy link

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

Copy link
Contributor Author

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}
Copy link

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

Copy link
Contributor Author

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 {
Copy link

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

Copy link
Contributor Author

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.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duh... ignore me.

Copy link
Contributor Author

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{} {
Copy link

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
Copy link

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?

Copy link
Contributor Author

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.

Copy link

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
Copy link

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.

Copy link
Contributor Author

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?

Copy link

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 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duh... ignore me.

@kat-co
Copy link
Contributor Author

kat-co commented Nov 24, 2016

$$merge$$

@jujubot
Copy link
Contributor

jujubot commented Nov 24, 2016

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju-testing

@jujubot jujubot merged commit 5ea7716 into juju:master Nov 24, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants