Java, Web and Mobile

Blog

Mocking framework comparison: JMockit

|
Java|Testing

JMockit is an open source framework including APIs for mocking, faking, and integration testing. It is licensed under the MIT License. The first stable release dates back to 2012; the latest release 1.31 is from March 2017. Compared to Mockito this framework is not younger so much. However, it has a very low distribution. This post will introduce JMockit’s core concepts and try to answer the question why and when to use JMockit.

This post is part of a series. The last article has given an introduction into core concepts of mocking as well as Mockito.

Using JMockit

Using maven we only need to add a new dependency to or pom.xml as you can see in listing 1.

Listing 2 shows a first very simple unit test using JMockit. Please note: I created a small demo project providing classes DemoService, DemoDAO, DemoEntity and so on. This project can be found at GitHub.

Running the test will give us a green result. So, let us have a look at the test code in detail. Class DemoService uses CDI to inject DemoDAO. Like Mockito, JMockit supports dependency injection. However, there are some slightly differences. The tested class needs annotation @Tested. This will tell JMockit to create a new instance of DemoService and inject needed dependencies. For injection to be performed the test class must also contain one or more mock fields declared to be @Injectable. Therefore, the field dao is initialized as mock and will be injected into the service object. Note that mock fields annotated only with @Mocked or @Capturing are not considered for injection. Like Mockito, JMockit’s dependency injection also works based on types. Having the same type for multiple fields will lead to unpredictable behaviour, too. In contrast to Mockito a missing dependency will result in failure of all tests in the current test class.

Now let’s have a look at the test method. Every JMockit based test has to follow a strict template that defines the method’s basic structure. There are three phases: The first phase is called Record phase. Here, one or more invocations on mocked types/instances are recorded. If you have no expectations, you can skip this phase. In the second phase, called Replay phase, the class or method which our test method is supposed to test is exercised. Any invocations to mocked methods/constructors that were previously recorded will now have a chance to be replayed. Third and last phase is the Verify phase. Now, we can explicitly verify that specific invocations to mocked methods actually happened (or not) during replay. Again, it is valid for this phase to be empty.

Looking at the concrete test method save() we can see that the Record phase is empty. Another fact is that you won’t see any asserts. This is correct, since JMockit uses an anonymous inner class of type Verifications for assertions. It may take a while to get used to the syntax: Assertions are made within the inner class’ constructor, which can be directly reached using double curly braces. So, in this context dao.update(entity) verifies that method update() of mocked object dao was called with concrete parameter entity. You can also check the number of invocations by assigning a value to field times directly after the method call (per default JMockit expects exactly one invocation).

Stubbing

If you need a stub, just create a mock and stub certain methods. To create a local stub you can add an annotated parameter to your test method. In listing 3, I added a second test that changes the behaviour of our DemoEntity object.

JMockit will produce and pass an initialized mock of type DemoEntity into our test case. To stub a method we need to define so called Expectations. The Expectations syntax is equal to Verifications. However, the Expectations block is the first code in our test method. So, stubbing method isNew() works like this: Call desired mock object’s method in Expectations constructor and tell JMockit the expected result using a value assignment directly after the first expression.

When it is getting more complex, you will need to use a Delegate as I did in listing 4.

Whenever method isNew() is called the delegate will be called, too. Delegate is an interface provided by JMockit not providing any methods to implement. So, the method’s name (delegate() in our case) can be randomly choosen, the return type must match the stubbed method’s return type. This is a little bit confusing for the programmer (and the compiler as well).

Argument matching

So far, all verifications just used exact matching of input parameters. In general, you should use exact matching where you can. Nevertheless, there are use cases where you want to match a method parameter against a wider range of values. The test in listing 5 ensures that the DAO’s method load() is never called for any instance of DemoEntity.

Instead of our concrete instance entity, we pass a kind of wildcard to method load. Such wildcards can be created using factory methods provided in class Verifications. So, these protected methods can be used without any additional imports. There are several methods for checking equality, simple string operations and so on. If you need a more sophisticated matching, you can write an own matcher using method withArgThat().

Argument capturing

If you want to perform further assertions on parameters passed to a mock, you will need to use a Capture. Using Captures you are able to use JUnit’s asserts within the Verifications block, which might feel more familiar. Listing 6 demonstrates how to use Captures.

Within the Verifications block, we create an uninitialized instance of type DemoEntity. Then we tell JMockit that when dao.update() is called, the passed parameter should be captured an assigned to this instance. This is done using method withCapture() provided in class Verifications. Now we can do asserts on the captured value. If you expect more than one invocation, use withCapture(List<T>) to get a list of all captured parameters.

Verifying execution order

Sometime you need to ensure that certain operations are performed before others will. For example, in context of our demo service we want to ensure that the entity’s validation method is called before passing the entity to the dao. Listing 7 shows how to implement that using JMockit.

Instead of using a Verifications block we will use the type VerificationsInOrder, the remaing syntax is equal to the other examples. Using VerificationsInOrder the order of assertions must match the order of the actual method invocations in our test. VerificationsInOrder permits unstated method invocations between or after the stated ones. If you are looking for an exact matching just use FullVerifications.

Mocking of static, final or new

You need to mock a static final method? Well, no problem! JMockit does not care about these modifiers. This is a big plus for the framework. In addition, you can even do assertions on objects created using keyword new within a tested method as shown in listing 8. Please note the unused parameter of the test method – we need this to tell JMockit to oberserve our DemoEntity instances.

Summary

JMockit is a powerful framework to enhance unit tests. Compared to Mockito the JMockit syntax is a little bit harder to write and to get used to. Indeed, the shown code format sequencing several commands within one line will be disrupted by every default code formatter. In return, the clear separation of expectations, invocations and verifications helps to read the test code. A big point for JMockit is the ability to test static or final methods (which is a No-Go using Mockito).