JMockit An automated testing toolkit for Java

Getting started with JMockit

The toolkit is provided as a versioned zip file that contains everything (jars, sources, documentation, 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. The mocking APIs and the code coverage tool are documented through a tutorial, API documentation, and several sample test suites.

Using the JMockit full distribution

Follow these instructions to start using JMockit:

  1. Download the full distribution for the current release. Alternatively, you can clone the GitHub repository.
  2. Unpack the zip file to any directory. This will create two sub-directories, one for the jmockit1.org GitHub repository (with source files, sample test suites, and pre-packaged jar files), and the other for the jmockit.github.io GitHub Pages repository (with HTML files for the tutorial, the API documentation, and other pages). To build the project with Maven (3.2 or newer), simply use the "jmockit1.org/main/pom.xml" and "jmockit1.org/coverage/pom.xml" files from the full distribution, or from a GitHub fork.
  3. 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 file.
  4. Depending on the choice of test framework (JUnit or TestNG):
  5. 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). API documentation is also available in the "jmockit.github.io/api1x/" directory, as well as online.

For 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 APIs

The JMockit mocking APIs can be used in tests written with JUnit 4 (version 4.5 or newer) or TestNG (version 6.2 or newer). Lets now see how mocking is done with the available APIs, which are 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).

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 done with the Mockups API. The next test shows an example.

@Test
public void fakingExample()
{
   new MockUp<MyCollaborator>() {
      @Mock
      boolean doSomething(int n, String s, ComplexData otherData)
      {
         assertEquals(1, n);
         assertNotNull(otherData);
         ...
         // Return (if non-void) or throw the result we want to produce for
         // this invocation of the mocked method:
         return otherData.isValid();
      }

      // Other mock or regular methods, if needed...
   };

   // Exercise code under test normally; calls to MyCollaborator#doSomething will
   // execute the mock method above.
   ...
}

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 mocked class.

A MockUp<T> subclass can also 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 "jmockit-mocks" system property or providing a "jmockit.properties" configuration file.

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.

More information

The examples above give only a brief overview of the available mocking/faking APIs. 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. Finally, there are hundreds of JUnit sample tests available under the "jmockit1.org/samples" folder, which use nearly everything that is available in the APIs.