Getting started with the JMockit Testing Toolkit

The toolkit is provided as a versioned zip file that contains everything (jars, sources, documentation, and Maven configuration files), and also as a set of Maven artifacts deployed to the Maven Central repository (under "<groupId>com.googlecode.jmockit</groupId>"). The mocking APIs and other tools 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 do an anonymous SVN checkout of the entire project.
  2. Unpack the zip file to any directory. This will create the "jmockit" directory containing the library jars, source files, samples, API javadocs, and additional documentation. If you want to build the JMockit project itself using Ant, then you should also download and unpack (to the "jmockit" dir) the jmockit-libs.zip file. To build with Maven, simply use the "jmockit/main/pom.xml" file from the full distribution, or from a SVN checkout.
  3. Add the library file jmockit.jar to your classpath (in your Java IDE project, Ant build file, and so on, as required).
  4. Depending on the JDK used and the JUnit/TestNG choice:
  5. Optionally, configure your IDE to find API source code and Javadoc comments in this same jmockit.jar file. API documentation in HTML is also available in the "jmockit/www/javadoc" directory, as well as on-line.

For instructions on the use of JMockit from an Ant build script, see the relevant section in the JMockit Tutorial. For Maven, see this section.

Using the mocking APIs

The JMockit mocking APIs can be used in tests written with any of the popular testing frameworks: JUnit 4 (version 4.5 or newer, including support for junit.framework.TestCase) and TestNG (version 5.14 or newer). Lets now see how mocking is done with the available JMockit APIs, which are all imported from the mockit package.

Creating a "mock object"

In a test class, declare a mock field of the type you wish to mock, annotating it with a JMockit annotation such as @Mocked or @Injectable. When mocking a class, the latter annotation means that only the instance assigned to the mock field will have mock behavior; if it is not applied, all instances of the mocked class will be mocked by default.

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 template 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 and quite useful. In fact, 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 & Verifications API for behavior-based testing:

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

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

      // Verify phase: expectations on mocks are verified; empty if there is 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 (but with implicit, automatic, verifications - otherwise no behavior would be tested). 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

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

   @Test
   public void aTestMethod(@Mocked final MyCollaborator mock)
   {
      new NonStrictExpectations() {{
         mock.getData(); result = "my test data";
         mock.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.
      ...
   }

There are two classes that can be used to define "expectation blocks": Expectations and NonStrictExpectations. The difference is in the default behavior for the recorded expectations. In the first case, all expectations associated to mocked types used in the block will be strict by default, meaning that the invocations are expected to occur during the replay phase in the same order as they were recorded, and that invocations not recorded are expected to not occur. In the second case, expectations are always non-strict, meaning that the invocations to mocked types, whether recorded or not, are allowed to occur in any order and in any number, including not at all.

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 actual values or objects being provided for the remaining ones.

Verifying expectations

When one or more types get mocked non-strictly in a test, we often end up with a non-empty verification phase. (If, on the other hand, all mocked types used in the test have only strict expectations, then all invocations get implicitly and automatically verified at the end of the test, with no explicit verify phase.) To explicitly verify invocations to non-strict mocked types/instances, we can write one or more verification blocks in the test. This allows us to make sure that the invocations we care about actually occurred during the replay phase.

   @Test
   public void aTestMethod(@Injectable final MyCollaborator mock)
   {
      // Non-strict expectations are recorded, or perhaps there are no expectation blocks at all.
      ...

      // Code under test is exercised.
      ...

      new Verifications() {{
         // If no new instance of the mocked class should have been created with the
         // no-args constructor, we can verify it:
         new MyCollaborator(); times = 0;

         // Here we verify that the "MyCollaborator#doSomething()" method was executed at least once:
         mock.doSomething();

         // Another verification, which must have occurred no more than three times:
         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).

State-oriented mocking, fake implementations

Sometimes you are more interested in checking the argument values passed to a mocked collaborator, instead of checking that the invocation to the collaborator was made from the client/tested method. Of course, you can check argument values through a recorded or verified expectation, but it becomes more difficult when those values are complex. In such cases it may be easier to use the MockUp<T> generic class, as the next test shows.

   @Test
   public void stateBasedTestMethod()
   {
      new MockUp<MyCollaborator>() {
         @Mock(invocations = 1) // (the invocation count constraint is optional)
         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...
      };

      // Exercise the code under test normally; calls to MyCollaborator#doSomething will execute
      // the mock method above; if more or less than one such invocation occurs, the test fails.
      ...
   }

The @Mock annotation marks those methods in the mock-up class which are meant to provide mock/stub implementations for the corresponding methods (of the same signature) in the mocked class. If no invocation count constraint is specified through attributes of the @Mock annotation, then any number (including zero) of invocations will be allowed.

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.

More information

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