- THE ART OF PRETENDING -

For years the industry standard of mocking on the JVM has been Mockito. Mockito is a wonderful library that really speeds up your testing by allowing you to create mocks in a very simple way. That being said, it does have its drawbacks, for which different strategies need to be deployed to keep your code testable. The main drawbacks are statics and finals. Final classes cannot be mocked, nor final methods, and also static methods are a no-go. To work with these type of things we need to wrap it, and copy the signature in a non final, non static way.

I have a great adversity against statics, I've devoted an entire post about it, in short; It hides dependencies and brings so little convenience at the costs of its drawbacks. Finals on the other hand have purpose, it helps messaging the goal of a class or method. Java is one of the few languages where classes and methods are open/virtual by default and have to be closed/final by explicit action. In (for example) Kotlin, everything is final by default, if you do not want something to be final, you should use the open keyword.

No matter if you follow the principle of making things final, static or not, if you are using Mockito the decision has been made. This mocking framework demands that everything is non-final, demands that everything is designed to be extended, since it might need to be mocked away. We should be able to improve upon this, and by the name of this post, you should be able to guess which framework will save the day. JMockit will help us with our impediments, and will give some other nifty benefits as well!

Arrange, Act, Mockito

The basics of writing a unit test shouldn't be too hard. You prepare some things, then you execute, and then you check if what you think should have happen happened. So let's start with something simple. We have a class that will check for us what the interest is on a savings account.

public final class InterestManager { public final double getMonthlyInterestPercentage() { fancyNetworkCallWithStaticMethod(); return 5; } private static void fancyNetworkCallWithStaticMethod() { try { Thread.sleep(5000); } catch (InterruptedException ignored) { } } }

Basically this class does what every kitchen salesman does. It goes to the back too look important, and then returns with a figure it already knew. Clearly this is just some hypothetical code. Next we have a class that calculates the interest given a sum of money.

public class InterestCalculator { public static final int MONTHS_PER_YEAR = 12; public double getYearlyInterest( final InterestManager interestManager, final double savings) { double monthlyInterestPercentage = interestManager.getMonthlyInterestPercentage(); double ratio = monthlyInterestPercentage / 100; double base = 1 + ratio / MONTHS_PER_YEAR; double power = Math.pow(base, (double) MONTHS_PER_YEAR); double interest = savings * (power - 1); return interest; } }

The getYearlyInterest method uses a InterestManager to get the current monthly interest rate and then calculates the yearly interest based on a monthly percentage. Testing all of this in one go isn't too hard, but how would you go about this if you want to test either class in isolation? And what about the executing time, since there is this sleep in interestManager.getMonthlyInterestPercentage() ?

public class InterestCalculatorTest { private InterestCalculator calculator; @Before public void setUp() { calculator = new InterestCalculator(); } @Test public void shouldCalculateCorrectAmountOfInterest() { InterestManager interestManager = new InterestManager(); double yearlyInterest = calculator.getYearlyInterest(interestManager, 5000); assertThat(yearlyInterest).isEqualTo(255.81, within(0.005)); // We want to ignore values below 1 cent } }

Alright, so this succeeded. As it turns out, if you have 5000 on the bank, you'll get 255.81 at a 5% monthly interest rate. This test is depending on Calculator , in such a small test-scope it really isn't a problem, however it does take over 5 seconds to complete. Try to imagine a much larger scope where you often encounter these kind of things. Now let's mock out Calculator using Mockito...

public class InterestCalculatorTest { @Mock private InterestManager interestManager; private InterestCalculator calculator; @Before public void setUp() { initMocks(this); calculator = new InterestCalculator(); } @Test public void shouldCalculateCorrectAmountOfInterest() { when(interestManager.getMonthlyInterestPercentage()).thenReturn(5d); double yearlyInterest = calculator.getYearlyInterest(interestManager, 5000); assertThat(yearlyInterest).isEqualTo(255.81, within(0.005)); // We want to ignore values below 1 cent } }

Doesn't work, for two reasons. First, InterestManager is final, so mockito can't mock it. The combination of line 3, 4 and 10 will fail. Secondarily, even if InterestManager wouldn't be final, it still would fail, this time at line 16, because final methods cannot be mocked by Mockito. Also statics will raise issues, so goodluck mocking out Thread.sleep(...) if you want to test InterestManager .

JMockit to the rescue

The notation of JMockit might be a bit weird, but you'll feel at ease with it in due time. Also scoping might freak you out at first, but also this is a blessing once you get the hang of it. Being able to mock finals, statics and everything else is amazing. Not only mocking expected behaviour, but also verifying execution. Ever wanted to check if a constructor was called with certain parameters?

Lets use the same example as before, but rework it with the JMockit touch.

public class InterestCalculatorTest { @Tested private InterestCalculator interestCalculator; @Test public void shouldCalculateCorrectAmountOfInterest( @Injectable final InterestManager interestManager) { new Expectations() {{ interestManager.getMonthlyInterestPercentage(); result = 5; }}; double yearlyInterest = interestCalculator.getYearlyInterest(interestManager, 5000); assertThat(yearlyInterest).isEqualTo(255.81, within(0.005)); // We want to ignore values below 1 cent } }

The above example packs some nice things rather dense. Take a look at lines 3, 8 and 10 through 13. We see in order: Injection of class under test, scoped mocks and expectations.

Annotations

There are various powerful annotations available to your disposal when using JMockit. Two of these are in the above example @Tested and @Injectable .

@Tested is a convenience annotation that will instantiate the class under test. It will try to satisfy all dependencies of the class's constructor, and if there are more than one constructor, it will use the most demanding constructor it can satisfy. If you would be using @Inject on your class under test, for example if you would be using Dagger, then it will choose that constructor. To satisfy the dependencies, JMockit will use types annotated with @Mocked , @Injectable and @Capturing . If still not all dependencies are satisfied, it will try to instantiate the dependencies themselves, and if that fails, they will be null .

@Injectable is best compared with Mockito's @Mock , it creates a mocked instance of the required type and you can use it to mock behaviour, verification and inject into your class under test. It will be able to mock all non-static things, including finals.

@Mocked will mock out the class entirely, including statics and whatnot. The entire bytecode is replaced, which means that any instance of this class by replaced by a mock. So if you would new an instance, it will be a mock and not an actual instance of that class. You need to be aware of this! It allows you to mock the constructor as well :)

@Capturing goes even a bit further than @Mocked , also any subclass of the annotated type will be a mock. This goes for interfaces as well, any implementation of a mocked interface will be replaced by a mock.

Scoping of mocks

So with this unleashed power of the levels of mocks we need to be a bit more aware on how to use these. If you would just use @Mocked on the fields in your test code any instance of that type will become mocked. Also JMockit will not care about particular instances of this type, they will be treated all the same. @Injectable knows about instances, but sometimes you do need more. Therefore scoping is introduced. The code snippet below is from the earlier example, it shows scoping in action. By using annotations on test parameters instead of fields we can limit the scope. Only during that particular test the particular behaviour is applied. So you can choose - per test - if you want to mock out the entire class, or also all of its subtypes, or just one instance.

@Test public void shouldCalculateCorrectAmountOfInterest( @Injectable final InterestManager) { ... }

Defining expected behaviour

What can we actually do with all these mocks? We have various levels, various scoping, now what? Forget about things being static or final, let's assume we choose the right type of mock. The notation is all the same with JMockit.

new Expectations() {{ interestManager.getMonthlyInterestPercentage(); result = 5; }};

This is an Expectations block, which you use to record what you expect to happen, and how to react on it. Be aware of the unusual {{ .. }} notation. In essence you are creating a new instance of the abstract class Expectations , and give it an initialization block. Below code does the same, but above code just looks nicer.

new MyExpectations(interestManager); ... class MyExpectations extends Expectations { public MyExpectations(final InterestManager interestManager) { super(); interestManager.getMonthlyInterestPercentage(); result = 5; } }

In the Expectations block we just call the method we expect to be called by the class under test, and then set the return value we want to result . If the method is a void method, then omit the result field. If you want to define additional expectations, then you can just continue in the same block.

new Expectations() {{ someMock.someMethod(anyDouble, anyString); result = new RuntimeException(); someotherMock.someOtherMethod(withAny(instanceOfComplexObject)); result = 2; interestManager.getMonthlyInterestPercentage(); result = new Delegate() { public double someMethodWithMatchingSignature() { return 5; } }; }};

Sometimes you do not care with what value your method will be called, in that case you can just say anyDouble , or just withAny(...) if the object is complex (and give it any instance of the complex object, could be a mock as well). The above example also shows how you can add some logic to the result value. You can assign to result an instance of Delegate , which needs 1 single public method that should match the signature of the method you are expecting. This behaviour is analogous to Mockito's doAnswer .

The Expectations blocks are not exactly the same as when with Mockito. When using expectations, JMockit actually expect each of the recorded expectation to happen atleast once. By giving an integer parameter to the constructor of Expectations you can tell JMockit that you want it to happen at least 2, 3 or n times. Next to Expectations you also have StrictExpectations and NonStrictExpectations . The strict version expect exactly the amount of times specified, by default this is 1. Non strict will expect the recorded expectation 0 or more times, which is the most like Mockito's when . Not satisfying the number of required invocations of an Expectations will fail your test.

Verifying what has happened

Often you not only want to set expectations, but you want to verify is something has happened, for example has your listener been informed about some update? Or has my static Thread.sleep(...) function been called? For this the Verifications block exists, which follows the same {{ .. }} notation as the Expectations block.

@Test public void shouldCallThreadSleep(@Mocked final Thread thread) throws InterruptedException { InterestManager interestManager = new InterestManager(); interestManager.getMonthlyInterestPercentage(); new Verifications() {{ Thread.sleep(5000); }}; }

JMockit also allows for capturing things, often used to capture listeners and such. To do this use the Verifications block and, first make a list of the type of object you want to capture - which is a list of Thread.UncaughtExceptionHandler in the below example. Next just call the method with the list wrapped in withCapture(...) , the list is then filled with all the actual invocations.

@Test public void shouldCaptureSomething( @Mocked final Thread thread, @Injectable final Thread.UncaughtExceptionHandler handler) throws InterruptedException { Thread.setDefaultUncaughtExceptionHandler(handler); new Verifications() {{ List<Thread.UncaughtExceptionHandler> handlerList = new ArrayList<>(); Thread.setDefaultUncaughtExceptionHandler(withCapture(handlerList)); assertThat(handlerList).containsExactly(handler); }}; }

Mock away everything and the kitchen sink

Ok.. last thing, just to blow your mind if it hadn't happened already. You can mock away anything. This includes the constructor. Constructors! You can finally actually test factories. You can verify if a constructor was called with the proper parameters.

But wait, there is more. You can also inject your mock objects into legacy code this way! See below, it is almost the same example as earlier, but instead of injecting the InterestManager instance, it is newed inline.

public double getYearlyInterest(final double savings) { InterestManager interestManager = new InterestManager(); double monthlyInterestPercentage = interestManager.getMonthlyInterestPercentage(); double ratio = monthlyInterestPercentage / 100; double base = 1 + ratio / MONTHS_PER_YEAR; double power = Math.pow(base, (double) MONTHS_PER_YEAR); double interest = savings * (power - 1); return interest; }

So let's inject our mock InterestManager using an Expectations block:

@Test public void shouldCalculateCorrectAmountOfInterest( @Mocked final InterestManager interestManager) { new Expectations() {{ new InterestManager(); result = interestManager; interestManager.getMonthlyInterestPercentage(); result = 5; }}; double yearlyInterest = interestCalculator.getYearlyInterest(5000); assertThat(yearlyInterest).isEqualTo(255.81, within(0.005)); // We want to ignore values below 1 cent }

Conclusion

Amazingk... a unified notation to mock, define and verify any method on any class. Final, static, or just regular. Did you realize that new is also a form a static method? You can mock out and verify calls to constructors, in code under test. You can actually insert mocks in legacy code that was never designed to be tested!

JMockit heavily relies on bytecode instrumentation, this way it can redefine classes, even after they have been loaded already. This is how JMockit can refine statics and finals. However there are some classes than are not eligible for this. The above example include Math , but this class cannot be mocked. Which is fine, since usually you do not need this (perhaps apart from Math.random() ). Other classes are classes like Boolean , Integer and String . Also these do not need mocking, but I just wanted to state it, since it is stated nowhere else. Also at this point in time it is not working well with Robolectric, due to the bytecode instrumentation (read more).

Basically there are no real downsides, and many many upsides. So start integrating JMockit in your tests and experience for you self how well it works.

References

If you want to read more, have other views, and find more interesting content:

The official JMockit docs

JMockit has extensive documentation about the why and how. You'll find way more info than described in this post, but it might be overwhelming to directly dive deep in.

Slide deck

Almost the same content as this post, but in slide format, including more awesome pictures.