JMockit An automated testing toolkit for Java

Getting started with JMockit

The toolkit is provided as a versioned zip file (with jars, sources, documentation, and Maven configuration files), and also as a set of Maven artifacts deployed to the Maven Central repository. It requires Java 6 or newer for test execution; tests must use JUnit or TestNG. The mocking/faking library has extensive API documentation; additionally, the APIs are described, with examples, in a tutorial which also covers integration testing support and code coverage.

Using the JMockit library

Follow these instructions to start using JMockit:

  1. Either add the library file jmockit.jar to your classpath (in your Java IDE project, Ant build file, etc.), or the org/jmockit/jmockit/1.x dependency to your Maven pom.xml or Gradle build.gradle file.
  2. Depending on the choice of test framework (JUnit or TestNG):
  3. Optionally, configure your IDE to find API source code and Javadoc comments in this same jmockit.jar file (or the jmockit-1.x-sources.jar and jmockit-1.x-javadoc.jar Maven artifacts).

For additional instructions on the use of JMockit from an Ant or Maven build, see the corresponding sections in the JMockit Tutorial: Ant, Maven.

Using the mocking API

The JMockit mocking API can be used in tests written with JUnit 4 (version 4.5 or newer), JUnit 5, or TestNG (version 6.2 or newer). Lets now see how mocking is done with this API, which is imported from the "mockit" package.

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 (rather than conventional "mock objects") 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 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 the field is not final) 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 final 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 final 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).

Instantiating and injecting objects to be tested

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"...

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 ExampleMockUp 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 applyMockUps()
{
   // Applies the mock-up by instantiating it:
   new ExampleMockUp();
}

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

// The applied mock-up is automatically discarded when out of scope.

The @Mock annotation marks those methods in the mock-up class which are meant to provide mock 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 "mockups" system property.

Mock-up 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 mock-up for the Java Mail API in a @BeforeClass method (or the test run by setting "mockups=testing.infrastructure.EmailMockUp"), so that each test can recover sent e-mail messages for verification.

More information

The examples above give a good overview of the available mocking/faking 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.