jostyee / gomock

Automatically exported from code.google.com/p/gomock
Apache License 2.0
0 stars 0 forks source link

Find matching call in reverse order #19

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
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