mock icon indicating copy to clipboard operation
mock copied to clipboard

Adding method to Controller allowing to check whether all expected calls have been made

Open FlorianLoch opened this issue 3 years ago • 4 comments

I want to be able to check whether all expected calls have been made before Controller#Finish() gets invoked as the code being tested is running asynchronously and I can only approximate when all calls will have been made.

This addition should allow it to check whether all expected calls towards the mock(s) have been made in an idempotent way. This is useful when testing asynchronous/non-deterministic things that aren't fully under the developers control (e.g., in end-2-end tests).

If necessary I can elaborate on my specific testing scenario.

Having such a method allows the user to write something like

require.Eventually(t, mockCtrl.AllExpectedCallsSatisfied, 60*time.Second, 100*time.Millisecond)

instead of having to wait for an approximated amount of time (which slows down the tests unnecessarily) in order to make sure all expected calls have been satisfied before Controller#Finish() gets invoked.

Why is this needed? Because right now AFAIU I have to add a sleep for an amount of time I approximate to be enough for my system to be done with its work. This is not nice for several reasons:

  • It's dangerous because my estimation could be too little and calls have not been made at that point
  • It's slow because I basically have to approximate very conservatively due to the problem described above

In order to check how feasible the implementation would be I already coded a proposal that I would be happy to open a PR for: https://github.com/golang/mock/compare/main...FlorianLoch:check-expectation-fulfilled?expand=1

FlorianLoch avatar Feb 07 '22 17:02 FlorianLoch

This issue (and the linked PR) ist open for more than 9 months now. Could I please get some official feedback? That would be nice :)

FlorianLoch avatar Nov 12 '22 11:11 FlorianLoch

Have you considered to use a WaitGroup as described in https://medium.com/@poy/gomock-and-go-routines-6a7c01d989d5 for signalling completion. I know it is actually a bit more difficult since you also need to unlock your waiting test thread on failures, if you do not want to timeout, which totally disturbs the user experience.

tkrop avatar Dec 25 '22 09:12 tkrop

That isn't a bad idea as a work around - but I guess having this addition in place would be simpler and more intuitive.

It's a little disappointing, that there is no actual activity on this issue and the related PR 🤷

FlorianLoch avatar Dec 25 '22 15:12 FlorianLoch

Here is a different use case for this feature that I would really like support for. Suppose I have this code I want to test:

type Callback interface {
	Callback(int)
}

func PerformCallback(cb Callback, par int) {
	cb.Callback(par)
}

Then I would like to do it like this:

func TestPerformCallback(t *testing.T) {
	ctrl := gomock.NewController(t)
	cb := NewMockCallback(ctrl)

	cb.EXPECT().Callback(1)
	PerformCallback(cb, 1)

	// Here it would be nice to assert that all expectations setup so far have been met

	cb.EXPECT().Callback(2)
	PerformCallback(cb, 2)
}

cwmos avatar Apr 14 '23 14:04 cwmos