There are various mocking frameworks for Java developers out there. In this post, we compare Mockito, EasyMock, and JMockit with a Java example to help you pick the right one for your needs!
What is mocking?
In software development, mock objects are simulated objects that mimic the behavior of real objects.
With mocking, you’ll define pre-programmed objects with expectations on how they should behave. These mock objects are configured to simulate the behavior of real ones. They help remove dependencies by replacing actual dependencies with implementations that the developer controls. This way, your tests focus on the tested code/behavior only: instead of calling a real object, your tests will just call this mock, making sure that the program gets the preconfigured response.
For instance, if your application needs to call a database or a web service, instead of actually calling these external objects, you can create a mock object that returns the data your application needs (or verifies the calls that have been performed on the mock). That way, you can test certain bits of your code in isolation, without any external dependencies (e.g. the behavior or state of external objects) interfering with your tests.
When to use mocking?
Mocks are widely used in unit testing since the main goal of unit tests is to test an object in isolation (only the respective unit). Mock objects help you focus on the “unit” being tested since they allow you to mock all other necessary objects, making sure they don’t interfere with the testing of the isolated unit.
But mocking can also be useful for integration testing, e.g. when “mocking out” individual pieces of the application to verify the interaction between certain components. Using mocks, you won’t have a full-blown system test at your hands when your goal is to only focus on selected components.
Mocks can also be useful during the development of production code: a component that is not yet implemented can simply be mocked for the time being.
In the context of mocking, we distinguish between three main types of replacement objects: mocks, stubs, and fakes. There are various definitions out there for each of these. Our team at Symflower uses the following definitions of these three concepts. Note that this post focuses on mocks only!
- Mock: Mocks are pre-programmed objects with expectations set on how they should behave. They are used as dependencies to return the desired output.
- Stub: Stubs return predefined answers for predefined questions. You’ll implement stubs with a logic and predetermine their behavior to substitute real behaviors.
- Fake: A fake is a simplified “real” implementation. What that means is that you may have a rudimentary implementation that actually works, but is not suitable for production – it is, however, good enough for testing purposes.
Why use mocking? Pros and challenges
The benefit of mocking is of course that you won’t need to develop and actually call the whole variety of external dependencies that your code may have. Instead, you’ll just provide the implementation with an object that returns the right values to let the implementation run, enabling you to verify the implementation in an economical way.
The main advantage of using mocking is that it can reduce the amount of code needed to set up your tests. If you use mocking, the readability and expressiveness of your tests will likely benefit.
The challenge in using mocks is to precisely simulate the behavior of your dependencies so that your tests stay robust. At the same time, you want to make sure you don’t overcomplicate your mocks since the whole point of using mocks is simplicity.
What is a mocking framework and why use one?
Mocking frameworks are used to isolate dependencies by helping you generate and control your replacement objects (mocks). They are useful if your goal is to write short and focused unit tests that really perform their intended purpose.
You’ll be using mocking frameworks alongside unit testing frameworks to tackle the testing of isolated bits of code. Mocking frameworks can make it easier to set the expected behavior of your mocks using predefined settings, making mocking faster. Some can also generate mocks for you automatically. Mocking frameworks also help you document which methods or lines of code are called, and you can also use them to track the execution order in cases where that may be useful.
Mockito vs EasyMock vs JMockit and a Java example
The concept of mocking is easier to understand through an example. In this section, we’ll be comparing the three most widely used mocking frameworks for Java: Mockito, EasyMock, and JMockit through an example. For the sake of brevity, let’s stick with a simple running example to show you how to do mocking with each of these frameworks:
Example:
In this running example, we are working with an interface Animal
that offers the single method compare
. The function under test resides in the class AnimalUtils
, is called compare
, and takes two input parameters of type Animal
:
public interface Animal {
int compare(Animal a);
}
public class AnimalUtils {
public static String compare(Animal a, Animal b) {
if (a.compare(b) == 0) {
return "equal";
} else if (a.compare(b) < 0) {
return "weaker";
} else {
return "stronger";
}
}
}
To run the following Java mocking examples, we are using JUnit 5 and Maven, so make sure to add the following extensions to your Maven file.
Dependency for JUnit5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
Surefire plugin to run JUnit 5:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
Generate mocks with Symflower
Adding imports and setting up mocks manually can take a while. Using Symflower to automatically generate these pieces of code can mean a significant productivity boost. Symflower supports the basic functionality of Mockito to create mocks. You can then manually fine-tune those mocks as you see fit, while having saved the time and effort costs of creating them. Try Symflower in your IDE!
Mockito
Mockito is popular because it is open-source and easy to use. It has a simple and clean API so that you can get started with mocking quite fast. It also comes with extensive documentation so even if you’re new to this framework, you shouldn’t have any problems getting started with it.
Mockito offers the support of a large community and has actually been voted the best mocking framework by Stackoverflow users. Besides stubs and mocks, Mockito lets you create spies which are similar to stubs but allow you to record how they were executed.
Developers like this framework because tests created with Mockito provide readability and produce clean verification errors. It’s a versatile framework that lets you mock both interfaces and classes in the test class. Mockito also has an extension called PowerMock which gives you access to more advanced mocking functionality such as mocking static methods.
In order to use Mockito, extend the Maven file with the following dependency:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
To test the “equal” case of our running example with Mockito, we can use the following code snippet:
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class MockitoTest {
@Mock
private Animal a;
@Mock
private Animal b;
@Test
public void compare() {
when(a.compare(any(Animal.class))).thenReturn(0);
String expected = "equal";
String actual = AnimalUtils.compare(a, b);
assertEquals(expected, actual);
verify(a, times(1)).compare(any(Animal.class));
}
}
In this JUnit5 test, the @ExtendWith(MockitoExtension.class)
annotation is used to enable the automatic initialization of mocks using the @Mock
annotation that Mockito provides.
when(a.compare(any(Animal.class))).thenReturn(0);
defines that mocka
should return 0 whenever itscompare
method is called.verify(a, times(1)).compare(any(Animal.class));
makes sure that the methodcompare
is called exactly once on mocka
.
EasyMock
EasyMock is also open-source and provides proxy objects that are dynamically generated at runtime to take the place of real objects. It is a flexible mocking framework that allows developers to use “nice”, “normal”, and “strict” mocks, which based on EasyMock’s definition differ in the following:
- **Nice mocks: the default behavior with
mock()
is to throw anAssertionError
for unexpected method calls. UsingniceMock()
changes that by allowing all method calls: aniceMock()
will return an applicable empty value (0, null, or false). A nice mock expects recorded calls in any order and returns null for other calls. - Normal or default mocks expect only recorded calls but in any order.
- Strict mocks: If you want your EasyMock object to check the order of method calls, you’ll need to use strict mocks. A strict mock expects only recorded calls and they should be replayed in their recorded order.
This provides full control over all interactions between EasyMock and your code. Note that EasyMock uses the Record-Replay-Verify model: use “record” to set expectations for the mock object, “replay” to return the recorded results, and “verify” to check that all recorded expectations have been returned and that no other, unexpected calls have been performed on the mock.
EasyMock comes with an excellent getting started guide, documentation, and a full API for browsing, so like Mockito, it’s easy to get started with. That said, it is not as widely used as Mockito, so the community supporting it is significantly smaller. The PowerMock extension mentioned above also works for EasyMock.
In order to use EasyMock, extend the Maven file with the following dependency:
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
Then, our running example continues as follows with EasyMock:
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.*;
import org.easymock.EasyMockExtension;
import org.easymock.Mock;
import static org.easymock.EasyMock.*;
@ExtendWith(EasyMockExtension.class)
public class EasyMockTest {
@Mock
private Animal a;
@Mock
private Animal b;
@Test
public void compare() {
expect( a.compare(b)).andReturn(0);
replay(a);
String expected = "equal";
String actual = AnimalUtils.compare(a, b);
assertEquals(expected, actual);
verify(a);
}
}
For EasyMock, first the expected calls are defined: (expect( a.compare(b)).andReturn(0);)
. By calling the method replay(a);
we are telling EasyMock that the actual testing starts now. Finally, the call to verify(a);
makes sure that all expected method calls on mock a
have actually taken place.
JMockit
Believe it or not, JMockit is also open-source! It supports mocking, faking, and integration testing and comes with a handy code coverage tool.
Like EasyMock, JMockit uses the “Record-Replay-Verify” model but is actually more flexible around setting expectations and verifications. With JMockit, you can mock pretty much anything – yes, that includes private methods, constructors, as well as static and final methods.
Like the two other options mentioned above, JMockit has great resources to help you get started, including an official tutorial and extensive API documentation. But since its scope is larger than that of other mocking frameworks, JMockit has a steeper learning curve. It is also a little behind on community support since fewer developers are using it, and it’s worth noting that JMockit hasn’t been actively developed for several years now.
In order to use JMockit, extend the Maven file with the following dependency:
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.49</version>
<scope>test</scope>
</dependency>
And guide the Surefire plugin by telling it where to find the JMockit jar:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>-javaagent:${settings.localRepository}/org/jmockit/jmockit/1.49/jmockit-1.49.jar</argLine>
</configuration>
</plugin>
</plugins>
</build>
Now, we are ready to write the first JMockit test:
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Verifications;
public class JMockitTest {
@Injectable
private Animal a;
@Injectable
private Animal b;
@Test
public void compare() {
new Expectations() {{
a.compare(b);
result = 0;
}};
String expected = "equal";
String actual = AnimalUtils.compare(a, b);
assertEquals(expected, actual);
new Verifications() {{
a.compare(b);
times=1;
}};
}
}
Note that JMockit uses a different annotation for initializing mocks: @Injectable
. In contrast to the other mocking frameworks, JMockit relies on anonymous classes to define expectations and verifications.
The expression newExpectations()
defines a new anonymous class that uses a default initializer to specify which method should be called on mock a
, and what its respective result should be. Similarly, the verification is done with an anonymous class whose default initializer makes sure that the compare
method of a
is only called once.
Summary: the basics of mocking & Java mocking frameworks
As it should be clear after reading our descriptions of Mockito, EasyMock, and JMockit above, mocking frameworks have pretty much the same feature set, with some nuances that set them apart and make them more useful for certain purposes.
Defining mocks can be done in different “flavors”:
- From when+verify calls in Mockito
- To the capture+replay style used by EasyMock with replay+verify
- Over to anonymous classes that are used to specify the expected calls and their verifications used by JMockit.
Since Mockito is the most widely used among these frameworks, Symflower also relies on Mockito when generating test suites. This test generation plugin can automatically create test templates, and may even be able to completely tackle unit test creation for you – and that includes full-fledged Mockito mocks! Check out Symflower in your IDE.