Description
I guess the main thing is to split the mock object itself from the mock configuration object. That would mean a breaking API change, but the fix will be trivial and easily automated.
Currently we use the same object both to set expectations and as a mock. That bites us in many places, because a mock must be a subclass of the class it mocks, but for the configuration object the mocked class signatures might be too tight.
So, for a class X extends Y { int m(int v); ...}
we will have something like
// generated file
class MockXConfig {
// all Xs methods (including inherited ones):
Expectation<int> m(Matcher<int> v);
// ...
}
class MockX extends Mock<MockXConfig> implements X {
// doesn't have to override anything.
MockX() : super(MockXConfig()) {}
}
and make when
return a configuration object for a mock. So stubbing becomes
when(mock).m(any).thenReturn(1);
instead of
when(mock.m(any)).thenReturn(1);
Personally I like the existing syntax more. But this allow us to overcome a number of problems:
- No overrides;
- => No need to revive default argument values.
- No need to came up with return values;
- => No need for dummies for stubbing (will still need them for nice mocks though, but I think nice mocks are ok to only be "best effort nice".
- I didn't put a lot of thought into it yet, but we likely could do something reasonable for private types as well.
No sure if it makes a lot of sense to re-write the existing codegen though, we might want to target macros directly (still have to investigate if it's even feasible to re-implement Mockito with macros though).