Getting started | About | Tutorial | Samples | API | Source | Issues | Community | History |
---|
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.
Follow these instructions to start using JMockit:
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.
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.
jmockit.jar
(or the equivalent Maven
dependency) appears before JUnit in the classpath.
Alternatively, annotate test classes with
@RunWith(JMockit.class)
.
attach
" native library.
jmockit.jar
(or the equivalent Maven
dependency) to the classpath.
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.
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.
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.
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.
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.
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).
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.
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.