golang / mock

GoMock is a mocking framework for the Go programming language.
Apache License 2.0
9.26k stars 608 forks source link

Support stacking mocks on top of real implementations #597

Open chawld opened 2 years ago

chawld commented 2 years ago

Allow stacking mocks on top of real implementations (or other mocks). If a call doesn't match an expectation in one layer, it can defer the call to the next layer. If none of the layers expect such a call, the call can be deemed unexpected and trigger a failure.

One use case of this is for error injection in tests. A test can stack a mock on top of a real implementation and inject errors. This can be done with gomocks today as well, but it requires the test to mock any/all other methods it may invoke on the mock. The real implementation backing the mock can provide the "default" implementation the test needs.

One way to implement this is for mockgen to (optionally) build stackable mocks such that

  1. The mock constructors take an optional backing implementation.
  2. If a call is expected, it is handled as it is today.
  3. If a call is not expected and a backing implementation is available, the call is "forwarded" to the backing implementation
  4. If a call is not expected and a backing implementation is not available, the call is handled as an unexpected call is handled today.

I have a PR in for fork of this repo which such an implementation along with examples: https://github.com/chawld/mock/pull/1

codyoss commented 2 years ago

I will leave this issue open for discussion. I am not sure this is something we should be adding to the API though. The EXPECT API is explicit on purpose. If you don't want you a certain method to use a behavior of a real impl you can always just call the impl as the mocks Return value.

chawld commented 1 year ago

Hey @codyoss, sorry for the delay in responding to your previous post.

For large interfaces, adding a pass-through from mock to real implementation for each method is cumbersome for large interfaces (e.g. cloud services) and increases test upkeep effort - changes in signatures of uninteresting methods or new method calls require test code to be updated. It also reduces test code readability - a reader has to parse through all the expected pass-through call handlers.