Closed umputun closed 3 years ago
I am personally not convinced, that the argument of having to split the declaration and the implementation is worth the additional complexity of the proposed flag. If you don't like the assignment of the functions one by one, you could even go for:
var p1 *ProviderMock
p1 = &ProviderMock {
EventsFunc: func(ctx context.Context) <-chan ProviderID {
evCount := len(p1.EvensCalls())
....
},
}
well, this doesn't resolve the split, i.e. declaration in your example is still a separate step from the actual implementation.
Personally, I think the simpler "user interface" is worths it, as we get rid of this artificial split and won't need the len call for something that essential and useful. From my experience, many non-trivial tests need some sort of state, and having this count easily accessible will make usage of moq more pleasant. I don't think the implementation will add any significant amount of code either.
In non trivial test, where my mock needs to respond differently in multiple subsequent calls (where the number of calls would become handy), I normally use a pattern with a list (slice) of responses (could also be a list of functions that return the necessary response values) where on every request, the first item is taken from the list. This looks more or less like this:
type Response string
responseQueue := []State{ "initial", "running", "finished" }
p1 := &ProviderMock {
EventsFunc: func(ctx context.Context) Response {
is.True(len(responseQueue) > 0) // EventsFunc was called when queue was depleted
// Pop response
resp := responseQueue[0]
responseQueue = responseQueue[1:]
return resp
},
}
In my case, the responseQueue is often part of my test table. I really try to avoid any complex state handling logic in my mock, because for me, the mocks should be as simple as possible and easy to reason about. After all, we are not testing the code of the mock but the SUT (system under test), which depends on the mocks in order to perform its task.
is
in the above example refers to https://pkg.go.dev/github.com/matryer/is
thx, this is an interesting approach.
I have tried to implement POV and it wasn't hard to make it generate what I wanted. However, I missed an essential issue - as soon as I add an extra parameter count
to the generated mock signature, the mock doesn't match the interface anymore. This is a fairly fundamental problem that kills the idea altogether. Probably I could figure some workaround, but it is getting ugly fast, so I would close the ticket.
Thank you @breml for the helpful suggestions 🙂
Very often I need to alter the return value of the called mock function based on the sequence number (counter). Currently, it is possible to do this by maintaining an external count and incrementing it in the call itself. I mean smth like this:
Another way to achieve it is to use the provided FuncCalls() method, I.e. len(FuncCalls()) but this approach requires to split declaration and implementation, I.e one needs to declare mock first and add the function after this:
My proposal is to add an extra flag, something like
-count
adding a count parameter to each generated mock and the usage will be as simple as this:Let me know what you think of this idea and I could try to implement it if you like it.