JMockit An automated testing toolkit for Java

Getting started with JMockit

The toolkit is provided as a set of artifacts deployed to the Maven Central repository. It requires Java 6 or newer for test execution; tests must use JUnit or TestNG. The library has extensive API documentation; additionally, the APIs are described, with examples, in a Tutorial.

Using the JMockit library

Follow these instructions to start using JMockit:

  1. Add the org/jmockit/jmockit/1.x dependency to your pom.xml or build.gradle file.
  2. Depending on the choice of test framework (JUnit 4.x/5.x, TestNG):
  3. Optionally, configure your IDE to find API source code and Javadoc comments in the jmockit-1.x-sources.jar file (which either the IDE or Maven/Gradle can download from the Maven Central repository).

The JMockit Tutorial contains specific sections on the use of JMockit from a Maven, Gradle, or Ant build.

Instantiating and injecting objects to be tested

In this and other sections we show many example tests. They all use JUnit 4, but could just as well be written with JUnit 5 or TestNG. Imports are not shown; in the case of the JMockit APIs, they are all imported from the "mockit" package.

The @Tested annotation provides support for the automatic creation of an object under test, with its dependencies automatically filled with mocked and/or real instances. A test class can declare one or more fields for tested objects, as shown below.

public final class ClassUnderTest
{
   @Inject private Dependency dependency;

   public void doSomething(String someData) { ... }
}

public final class ExampleUnitTest
{
   @Tested ClassUnderTest testedUnit;
   @Injectable Dependency mockDependency;

   @Test
   public void exerciseUnitInIsolationFromDependency()
   {
      Data data = new Data();
      new Expectations() {{ mockDependency.findSomeData(anyString); result = data; }};

      testedUnit.doSomething("...");

      new Verifications() {{ mockDependency.sendNotification(); }};
   }
}

In the test above, the class under test is instantiated (through its no-args constructor) and initialized with a mock dependency, so that it can be tested in isolation. We can just as easily write an integration test, where dependencies are not mocked but recursively instantiated and initialized as tested objects themselves; for this, we simply specify the tested object to be fully initialized:

public final class ExampleIntegrationTest
{
   @Tested(fullyInitialized = true) ClassUnderTest sut;

   @Test
   public void exerciseTestedObjectsTogether()
   {
      Data data = new Data();
      // Save data into application database or other data store.

      sut.doSomething("...");

      // Verify notification was sent.
   }
}

We are not going to deal with the actions mentioned in the comments above in this brief overview, but don't assume they are necessarily difficult to achieve. The @Tested API hides a lot of power behind one seemingly small annotation. Even more, it can be used as a meta-annotation, so you can create your own annotations from it, such as "@SUT" (for "System Under Test"), or "@DataObject", or "@Dependency"...

Using the mocking API

Lets now see how mocking is done with this API. It is the largest one (three annotations, seven classes, and one interface), but that shouldn't be taken as a suggestion to use it in every test. On the contrary, mocking (as well as "faking", discussed in the next section) is best used in moderation.

Creating a "mock object"

In a test class, declare a mock field of the type you wish to mock, and annotate it with @Mocked, @Injectable, or @Capturing. The last two annotations imply the first, which may then be omitted. When mocking a class, @Injectable means that only the instance assigned to the mock field will have mock behavior; otherwise, all instances of the mocked class will be mocked.

import org.junit.*;
import mockit.*;

public class MyFirstJMockitTest
{
   // Mocked instances will be automatically created and assigned to annotated mock fields:
   @Mocked
   Collaborator mock1; // all current and future instances are mocked

   @Injectable
   AnotherDependency anotherMock; // only one particular instance is mocked

   @Test
   public void myFirstTestMethod()
   {
      // Any mock field can be used here or in any other test method of the test class.
   }

   @Test
   public void testMethodWithMockParameter(@Mocked YetAnotherDependency testSpecificMock)
   {
      ...
   }

   ...
}

The test class above shows something unusual: the second test method declares a parameter! Normally, JUnit/TestNG test methods are not allowed to have parameters. When using JMockit, however, such mock parameters are allowed. In general, it's best to use mock fields of the test class only when the mocked types are needed by most or all tests in the class. Otherwise, mock parameters with scope limited to a single test are preferred. JMockit will always take care of instantiating the mocked type and either assigning the instance to the mock field (provided it's a non-final instance field) or passing it as an argument when the test method is invoked by the test runner.

What exactly goes inside a test method?

The following template shows the basic structure of a JMockit test method, when using the Expectations API:

@Test
public void aTestMethod(<any number of mock parameters>)
{
   // Record phase: expectations on mocks are recorded; empty if nothing to record.

   // Replay phase: invocations on mocks are "replayed"; code under test is exercised.

   // Verify phase: expectations on mocks are verified; empty if nothing to verify.
}

Each test method can be divided in three execution phases. First, one or more invocations on mocked types/instances are recorded. (In fact, it is perfectly valid to not record any invocation at all - more on this later.) Second, the production code/class/unit which our test method is supposed to test is exercised, typically with a call to a single tested method. Any invocations to mocked methods/constructors that were previously recorded will now have a chance to be replayed. Third, the test method can explicitly verify that specific invocations to mocked methods/constructors actually happened (or not) during replay. Again, it is perfectly valid for this phase to be empty, with no explicit verifications. Note that we say "mocked methods/constructors". The mocking API handles mocked methods (of all kinds) and constructors in the exact same way: to record or verify expectations on them, you simply invoke them during the corresponding test execution phase.

Recording expectations

For the "record" phase of a test, we can write one or more expectation blocks, inside which invocations to mocked methods/constructors are recorded.

@Test
public void aTestMethod(@Mocked MyCollaborator anyCollaborator)
{
   new Expectations() {{
      anyCollaborator.getData(); result = "my test data";
      anyCollaborator.doSomething(anyInt, "some expected value", anyString); times = 1;
   }};

   // In the replay phase, the tested method would call the "getData" and "doSomething"
   // methods on a "MyCollaborator" instance.
   ...

   // In the verify phase, we may optionally verify expected invocations to
   // "MyCollaborator" objects.
   ...
}

Once mocked, all invocations to a mocked instance or to a mocked class are allowed by default, in any number and in any order. If an expectation is recorded, however, then at least one matching invocation is expected to occur from the code under test; if there is none, a "missing invocation" error will be thrown at the end of the test.

You may be wondering what are those field assignments in the example test above. This is indeed something that you won't see in any other mocking API. That said, it should feel very intuitive once the semantics are known: the result field takes the desired return value for the preceding invocation, while times takes the number of times the preceding invocation is allowed and expected to occur. (There is also a minTimes and a maxTimes field.) The result field also accepts a Throwable instance, which would cause the corresponding invocation in the replay phase to throw the specified exception or error.

Another interesting feature of the API is its support for argument matching constraints. The test above uses some of the special "any" fields, such as anyString, anyDouble, and so on. The API also provides a set of "with(...)" methods, such as withNotNull(), withSameInstance(T), etc. Arbitrary user-defined matchers can be provided through a call to the with(Delegate) method. Finally, it should be noted that, differently from most other mocking APIs, JMockit does not require a matcher for every parameter; any subset of parameters can have matching constraints, with regular values being provided for the remaining ones.

Verifying expectations

To explicitly verify invocations that occurred on mocked types and their instances, we can write one or more verification blocks in the test. This allows us to make sure that important invocations actually occurred during the replay phase.

@Test
public void aTestMethod(@Injectable MyCollaborator mock)
{
   // Expectations are recorded, if needed.
   ...

   // Code under test is exercised.
   ...

   new Verifications() {{
      // Verify the "MyCollaborator#doSomething()" method was executed at least once:
      mock.doSomething();

      // Even constructor invocations can be verified:
      new MyCollaborator(); times = 0; // verifies there were no matching invocations

      // Another verification, which allows up to three matching invocations:
      mock.someOtherMethod(anyBoolean, any, withInstanceOf(Xyz.class)); maxTimes = 3;
   }};
}

The Verifications API is quite rich and flexible. Besides the Verifications class shown above, which allows some invocations to be verified regardless of their order of execution, we have the VerificationsInOrder, FullVerifications, and FullVerificationsInOrder subclasses. The "InOrder" suffix simply means that the relative order of the invocations appearing inside the verification block will have to match the actual order of execution of corresponding invocations during replay. The "Full" prefix means that all invocations that occurred during replay must be accounted for (verified) inside the verification block (excluding those which are verified implicitly, if any).

Fake implementations

A different API is provided for substituting the original implementation of some method or constructor in a class with a fake one; this is the faking API. The next test shows an example.

public static final class ExampleFake extends MockUp<ExternalService>
{
   @Mock // fake implementation for a method of the same signature
   public boolean doSomething(int n, String s, ComplexData otherData)
   {
      // Return (or throw) a "fake" result for invocations to the method in the faked class:
      return true; // ... or whatever
   }

   // Other @Mock methods for other methods or constructors in ExternalService, if needed.
}

@BeforeClass
public static void applyFakes()
{
   // Applies the fake by instantiating it:
   new ExampleFake();
}

@Test
public void fakingExample()
{
   // Exercise code under test normally; calls to ExternalService#doSomething will
   // execute the fake method above.
   ...
}

// The applied fake is automatically discarded when out of scope.

The @Mock annotation marks those methods in the fake class which are meant to provide fake implementations for the corresponding methods (of the same signature) in the faked class. A MockUp<T> subclass can be used as a general-purpose fake implementation for the indicated type "T" (including final classes, classes with static methods, etc.). Such implementations can even be applied globally, by setting the "fakes" system property.

Fake classes providing partial fake implementations can be very useful in integration testing. They can be used in a supporting role when creating an integration testing infrastructure for complex application frameworks such as Spring, Hibernate, or Java EE. For example, we could apply a fake for the Java Mail API in a @BeforeClass method (or the test run by setting "fakes=testing.infrastructure.FakeEmail"), so that each test can recover sent e-mail messages for verification.

More information

The examples above give a good overview of the available APIs, but there is more. The JMockit Tutorial contains an extensive discussion of nearly all methods, fields, annotations, etc., with many examples. The API documentation provides a detailed specification for all API elements.