We all love to use mocks in our Java tests, right? Add the usual mock framework to your test dependencies, sprinkle a few mock
, when
and thenWhatever
calls in to your code, and happy days. You’re able to test things in isolation, and as an added bonus ensure your code is actually calling the stuff it’s supposed to be calling by verifying the mock afterwards. The sun is shining, life is good, and your code is tested to perfection.
But then the clouds roll in, and you have to test a final class. Or you need to mock out a static method in some legacy code. Or, horror, some code that directly calls new
on a class you want to mock.
You could hit up StackOverflow, where you’ll find that all these things are possible with existing frameworks, assuming you’re prepared to add in another dependency, use a ton of boilerplate, and refactor your (production) code a bit. Depending on which framework you’re currently using there are a ton of different ways you can kind of achieve what you need.
By now you’ve sunk another hour or two, and it’s still not quite working.
What if there was another way?
The other way
What if I told you there was a framework out there that let you take a final class, and just do this?
mockClasses(FinalClass.class); FinalClass sc = new FinalClass(); assertThat(sc.returnHello()).isNull(); assertMock(() -> sc.returnHello()).wasCalledOnce(); when(() -> sc.returnHello()).thenReturn("Goodbye"); assertThat(sc.returnHello()).isEqualTo("Goodbye"); assertMock(() -> sc.returnHello()).wasCalledTwice();
What if it also did statics, with the same API, and no extra dependencies?
mockClasses(ClassWithStatic.class); assertThat(ClassWithStatic.returnHello()).isNull(); when(() -> ClassWithStatic.returnHello()).thenReturn("Goodbye"); assertThat(ClassWithStatic.returnHello()).isEqualTo("Goodbye");
What if it even let you mock out constructors?
final RuntimeException rte = new RuntimeException("MARKER"); mockClasses(FinalClass.class); when(() -> new FinalClass()).thenThrow(rte); assertThatThrownBy(() -> new FinalClass()).isSameAs(rte);
What if we put all our arguments about whether we should be doing this kind of mocking to one side for now, because sometimes in life, you’re faced with a nail.
And when you’re faced with a nail, you need a hammer.
There’s one here: https://github.com/roscopeco/moxy
Or grab it with Maven (instructions on the Github page).