PowerMock and MockMaker: API change request.
See original GitHub issueHi guys,
I’ve taken a time for reviewing PowerMock code to find place where it use internal Mockito API. I’d like to discuss what could be done to avoid.
First think that I’d like to talk about it’s MockMaker. PowerMock uses it custom MockMaker, which it past was used only for two things:
- cache a class create by CgLib
- return fake
InternalMockHandler
for static mocks.
The first case is no more actual, because ByteBuddy uses current context ClassLoader, so MockClassLoader
is used. But the second case still actual. But investigation shows that returning fake InternalMockHandler
is required only for one case right now.
Method org.mockito.internal.exceptions.Reporter.noMoreInteractionsWanted(Invocation undesired, List<VerificationAwareInvocation> invocations)
tries to safelyGetMockName(undesired.getMock())
. Finally, call comes to org.mockito.internal.util.MockUtilisMock(Object mock)
. It tries to get MockHandler
for mock, but it mock is static and it’s not a PowerMockMaker, then null
is returned.
I was surprised that having PowerMockMaker
is required only for such thing. If speak, honestly, I don’t have any idea, how it can be fixed on Mockito site. Maybe you have any thoughts?
The second point, it’s a way how Mockito loads plugins. We had some discussion within #1006. Main point provided @podarsmarty (as for me main) that if there are two files org.mockito.plugins.MockMaker
in class path, then order of loading plugins are unpredictable. Such undetermined behaviour could introduce some fluky bugs, when for example one plugin specified in project and other in dependency jar. And for example it works, but later author of dependency jar make refactoring and change package or something like this. As result other plugin is loaded by Mockito and tests start failed.
For PowerMock it is issue, because is has own MockMaker
, which is required only if test runs with PowerMock. But, unfortunately, if PowerMock in class path it will be used always. If a developer wants to use mock-maker-inline
to be able to mock final without PowerMock, then it was impossible until PowerMock 1.7.0, where I added ability to specify MockMaker
to which PowerMockMaker
delegates calls. As for me, it will be good to have ability to separate custom MockMaker
and Mockito build-in MockMaker
. So custom MockMaker
could know which build-in MockMaker
should be used to delegate call if its required.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:1
- Comments:99 (53 by maintainers)
Top GitHub Comments
Thank you for assisting me. I’m also really happy to see how we move. It’s a big win for community!
@thekingnothing, do you live in Krakow? I spent most of my adult life in Krakow 😉
Thank you for reaching out to us so that we can work together. That’s how this should be done - we design the APIs between open source components so that our users get higher quality products (e.g. products that don’t break on version upgrade 😃.
I’m also surprised that those are the only issues with using Mockito’s private API. Something tells me there is more. Let’s keep working on this an expose all integration points.
Multiple methods from Reporter class attempt to use ‘safelyGetMockName’. I assume you use ‘noMoreInteractionsWanted’ as an example. Getting mock name is only used to make verification errors cleaner. It’s not a critical feature, without it the errors are still decent.
To get started, I suggest to hack Mockito code and return empty String if getting mock name throws an exception. This way you can push forward and identify other contention points. Once we get full picture we can design public API that will solve all use cases cases for integration with PowerMock.
I totally agree that random order of loading plugins is undesired. We don’t have a clean way of solving this problem at the moment. It needs more brainstorming. Ideas are welcome 😃
This is an interesting use case. Let me understand it: an author of custom MockMaker would like to have access to default Mockito MockMaker so that she can delegate some invocations to it? In Mockito we can introduce public API to expose the default mock maker (or means to obtain the default mock maker).