Sometimes, you program a mock for a general case, and would later reprogram it
for a special case, e.g.
mock.EXPECT().Load(gomock.any()).Return(nil, nil).AnyTimes()
mock.EXPECT().Save(e Entity).Do(func() {
mock.EXPECT().Load(e.Id).Return(e, nil)
})
This doesn't actually work however, because then the SUT does call Load with
the specified id, it will still be matched by the first general programmed
call, not the last specific programmed call. To actually get this to work, I
had to create something like this
loadCall := mock.EXPECT().Load(gomock.any()).Return(nil, nil).AnyTimes()
mock.EXPECT().Save(e Entity).Do(func() {
mock.EXPECT().Load(e.Id).Return(e, nil)
loadCall.Times(0)
loadCall = mock.EXPECT().Load(gomock.any()).Return(nil, nil).AnyTimes()
})
This is both redundant code, but it would also prone to race conditions if the
SUT was using multiple threads.
Other mocking frameworks, e.g. Moq for .NET matches the last programmed call
first, and I believe this evaluation order is more natural, as you would
normally program the general case first, and the specific case later. In
particular when working with context/specification test frameworks like ginkgo.
Of course, implementing loose mocks, as suggested in a different issue would
handle this _particular_ case.
Of course such a change to an existing framework would be a breaking change, as
test code could already be dependent on the current call match order. :| But
maybe it could be implemented as an optional setting with the default value set
to the current behavior?
Original issue reported on code.google.com by peterstr...@gmail.com on 1 Jun 2015 at 8:22
Original issue reported on code.google.com by
peterstr...@gmail.com
on 1 Jun 2015 at 8:22