In the JMockit toolkit, the Expectations & Verifications APIs provide rich support for the creation of
behavior-based unit tests.
The focus when doing this kind of testing is on the interactions between the unit under test and the other
units it depends upon. Such units of behavior are the classes, methods, and constructors defined in production code.
An interaction between two units always takes the form of a method or constructor invocation. The set of invocations from a unit under test to its dependencies, together with the argument and return values passed between them, define the behavior of interest for the tests of that particular unit. In addition, a given test may need to verify the relative order of execution between multiple invocations.
Note that a unit test only exercises the code of the tested unit. The implementation code behind dependencies is not meant to be exercised, since it's not part of the unit under test. So, the goal of unit testing is to test logical units of behavior in isolation from the actual behavior of its dependencies. Now, we typically do not want nor need to isolate a given unit from all its dependencies, but only from those that 1) already have (or will have, in case they are not implemented yet) their own unit tests in the same test suite; or 2) for practical reasons cannot be easily, quickly, or reliably executed in a unit test environment (because they write to a database, send emails, and so on). When coding the tests for a particular unit, we simply assume that its dependencies behave according to expectations. If they don't, it is the responsibility of their own tests to catch it.
Methods and constructors invoked from the unit under test, and which belong to a dependency/collaborator of said
unit, are the usual targets for mocking.
Mocking provides the mechanism that we need in order to isolate the tested unit from (some of) its dependencies.
We specify which particular dependencies are to be mocked for a given test (or tests) by declaring their types as
being mocked types.
That is, a mocked type should be the type of a dependency of the unit under test.
Such a type can be any reference type: an interface, an abstract class, a concrete
class, a final class, and so on.
By default, all methods of the mocked type will be mocked for the duration of the test.
If the declared mocked type is a class, then all of its super-classes up to but not including
java.lang.Object will also be mocked, recursively.
Therefore, inherited methods will automatically be mocked as well.
Again in the case of a class, all of its constructors will also get mocked.
Even more, whatever Java language modifiers happen to be applied to the methods/constructors of a mocked class, they
will still get mocked: private, static, final, native, it doesn't
really matter.
When a method or constructor is mocked, its original implementation code won't be executed for invocations occurring during the test. Instead, the call will be redirected to JMockit so it can be dealt with in the manner that was explicitly or implicitly specified for the test.
The following example test serves as a basic illustration for the declaration of mocked types. In this tutorial, we use many code snippets like this, where the parts in bold font are the current focus of explanation.
@Test
public void doBusinessOperationXyz()
{
...
new Expectations() // an "expectation block"
{
Dependency mockInstance; // "Dependency" is our mocked type for this test
...
{
...
// "mockInstance" is a mocked instance automatically provided for use in the test
mockInstance.mockedMethod(...);
...
}
};
...
}
As we will shortly see, there are several ways to declare mocked types, and also several ways in which the exact
semantics of mocking can be modified to suit the needs of a particular test or group of tests.
In most cases, such variations are specified through special annotations and their attributes:
@Mocked, @NonStrict,
@Injectable, etc.
These annotations can be applied to certain instance fields and to test method parameters.
An expectation is a set of invocations to an specific mocked method/constructor that is relevant for a given test. An expectation may cover multiple different invocations to the same method or constructor, but it doesn't have to cover all such invocations that occur during the test execution. Whether a particular invocation matches a given expectation or not will depend not only on the method/constructor signature but also on runtime aspects such as the instance on which the method is invoked, argument values, and/or the number of invocations already matched. Therefore, several types of matching constraints can (optionally) be specified for a given expectation.
When we have one or more invocation parameters involved, an exact argument value may be specified for each parameter.
For example, the value "test string" could be specified for a String parameter, causing the
expectation to match only those invocations with this exact value in the corresponding parameter.
As we will see later, instead of specifying exact argument values, we can specify more relaxed constraints which will
match whole sets of different argument values.
The example below shows an expectation for Dependency#someMethod(int, String), which will match an
invocation to this method with the exact argument values as specified.
Notice that the expectation itself is specified through an isolated invocation to the mocked method.
There are no special API methods involved, as is common in other mocking APIs.
This invocation, however, does not count as one of the "real" invocations we are interested in testing.
It's only there so that the expectation can be specified.
@Test
public void doBusinessOperationXyz()
{
...
new Expectations()
{
Dependency mockInstance;
...
{
...
// An expectation for an instance method:
mockInstance.someMethod(1, "test");
...
}
};
// A call to the unit under test occurs here, leading to mock
// invocations that may or not match specified expectations.
}
We will see more about expectations later, after we understand the differences between recording, replaying, and verifying invocations.
Any developer test can be divided in at least three separate execution phases. The phases execute sequentially, one at a time, as demonstrated below.
@Test
public void someTestMethod()
{
// 1. Preparation: whatever is required before the unit under test can be exercised.
...
// 2. The unit under test is exercised, usually by calling a public method.
...
// 3. Verification: whatever needs to be checked to make sure the exercised unit
// did its job.
...
}
First, we have a preparation phase, where objects and data items needed for the test are created or obtained from somewhere else. Then, the unit under test is exercised. Finally, the results from exercising the tested unit are compared with the expected results.
This model of three phases is also known as the Arrange, Act, Assert syntax, or "AAA" for short. Different words, but the meaning is the same.
In the context of behavior-based testing with mocked types (and their mocked instances), we can identify the following alternative phases, which are directly related to the three previously described conventional testing phases:
Behavior-based tests written with JMockit will typically fit the following templates:
import mockit.*;
... other imports ...
public class SomeTest
{
// Zero or more "mock fields" common to all test methods in the class:
@Mocked Collaborator mockCollaborator;
@NonStrict AnotherDependency anotherDependency;
...
@Test
public void testWithRecordAndReplayOnly(mock parameters)
{
// Preparation code not specific to JMockit, if any.
new Expectations() // an "expectation block"
{
// Zero or more local mock fields.
{
// One or more invocations to mocked types, causing expectations to be recorded.
// Invocations to non-mocked types are also allowed anywhere inside this block.
}
};
// Unit under test is exercised.
// Verification code (JUnit/TestNG asserts), if any.
}
@Test
public void testWithReplayAndVerifyOnly(mock parameters)
{
// Preparation code not specific to JMockit, if any.
// Unit under test is exercised.
new Verifications() {{ // a "verification block"
// One or more invocations to mocked types, causing expectations to be verified.
// Invocations to non-mocked types are also allowed anywhere inside this block.
}};
// Additional verification code, if any, either here or before the verification block.
}
@Test
public void testWithBothRecordAndVerify(mock parameters)
{
// Preparation code not specific to JMockit, if any.
new NonStrictExpectations() { // also an expectation block
// Zero or more mock fields.
{
// One or more invocations to mocked types, causing expectations to be recorded.
}
};
// Unit under test is exercised.
new VerificationsInOrder() {{ // also a verification block
// One or more invocations to mocked types, causing expectations to be verified
// in the specified order.
}};
// Additional verification code, if any, either here or before the verification block.
}
}
There are other variations to the above templates, but the essence is that the expectation blocks belong to the record phase and come before the unit under test is exercised, while the verification blocks belong to the verify phase. A test method can contain any number of expectation blocks, including none. The same is true for verification blocks.
The fact that anonymous inner classes are used to demarcate blocks of code allows us to take advantage of the "code folding" feature available in modern Java IDEs. The following image shows what it looks like in IntelliJ IDEA.
A mocked type can be introduced either through an instance field or a parameter declaration.
In the first case, the field belongs to the test class or to a mockit.Expectations
subclass (a local field inside an expectation block).
In the second case, the parameter necessarily belongs to a test method.
In all cases, a mock field/parameter declaration can use the mockit.Mocked annotation
(@Mocked).
The use of this annotation is optional for mock parameters and for mock fields declared inside expectation blocks.
It (or another annotation for mocked types, such as @NonStrict) is only required for
mock fields declared in the test class, in order to avoid confusion with other fields the test class might have that
are not intended for mocking.
All kinds of Java types are valid for mock fields and parameters, except for primitive types and for array types.
So, to make it clear, the following reference types are valid: interfaces, concrete classes, abstract
classes, final classes, enum types, and annotation types.
Note that this includes reference types from the JRE (belonging to one of the standard packages, like
java.lang, java.util, and so on).
For a mock parameter declared in a test method, an instance of the declared type will be automatically created by
JMockit and passed by the JUnit/TestNG test runner when calling the test method.
Therefore, the parameter value will never be null.
For a mock field, an instance of the declared type will be automatically created by JMockit and assigned to the
field, unless it's a final field.
In such a case, a value should be created and assigned to the field explicitly in test code.
This value can be null, though, which is perfectly valid for a mocked class if only constructors and
static methods are going to be called on it.
The mocked instances created by JMockit can be used normally in test code (for the recording and verification of
expectations), and/or passed to the code under test. Or they may simply go unused.
Differently from other mocking APIs, these mocked objects don't have to be the ones used by the unit under
test when it calls instance methods on its dependencies.
By default, JMockit does not care on which object a mocked instance method is called.
This is what allows the transparent mocking of instances created directly inside code under test, when said code
invokes constructors on brand new instances using the new operator.
The classes instantiated must be covered by mocked types declared in test code, that's all.
Finally, note that the mocked instances created by JMockit are similar to the traditional mock objects created by other mocking tools, but they are not the same. Every instance of a mocked type - whether created by JMockit or not - is mocked, for as long as that type remains mocked. With a more traditional mocking API, only the mock objects/instances created by the mocking tool are actually mocked. Most of the time, this makes little or no difference when writing tests, but it is something to keep in mind.
Suppose the unit under test needs to be given an object which implements two or more interfaces. Can we get a mocked instance which satisfies this requirement? One way to do it would be to create a test-specific interface which extends all the interfaces required by the tested unit, and then use that as the mocked type. There is a better way though, which does not require the definition of a new interface, as the following example tests show.
public interface Dependency // an arbitrary custom interface
{
String doSomething(boolean b);
}
public final class MultiMocksTest<MultiMock extends Dependency & Runnable>
{
@Mocked MultiMock multiMock;
@Test
public void mockFieldWithTwoInterfaces()
{
new NonStrictExpectations() {{
multiMock.doSomething(false); result = "test";
}};
multiMock.run();
assertEquals("test", multiMock.doSomething(false));
new Verifications() {{ multiMock.run(); }};
}
@Test
public <M extends Dependency & Serializable> void mockParameterWithTwoInterfaces(final M mock)
{
new Expectations() {{
mock.doSomething(true); result = ""
}};
assertEquals("", mock.doSomething(true));
}
}
In each of the tests above, two interfaces were mocked together: Dependency plus
java.lang.Runnable for a mock field, and Dependency plus
java.io.Serializable for a mock parameter.
We used the type variables MultiMock (defined for the whole test class) and
M (defined for a single test method) so that JMockit could know about the component
interfaces in each case.
For a given method with non-void return type, a return value can be recorded through the
Expectations#result field or through the Expectations#returns(Object) method.
When the method gets called in the replay phase, the specified return value will be returned to the caller (which
normally is the unit under test).
Either the assignment to result or the call to returns(Object) must appear right
after the invocation that identifies the recorded expectation, inside an expectation block.
If the test instead needs an exception or error to be thrown when the method is invoked, then the result
field can also be used. Simply assign the desired throwable instance to it.
In the rare case where a method actually returns exception or error objects, the returns(Object) method
will have to be used to avoid the ambiguity.
Note that the recording of exceptions/errors to be thrown is applicable to mocked methods (of any return type) as
well as to mocked constructors.
Multiple consecutive results (values to return and/or throwables to throw) can be recorded for the same
expectation, by simply assigning the result field multiple times in a row.
The recording of multiple return values and/or exceptions/errors to be thrown can be freely mixed for the same
expectation.
In the case of recording multiple consecutive return values for a given expectation, a single call to the
returns(Object, Object...) method can be made.
Also, a single assignment to the result field will achieve the same effect, if the value assigned to it
is a list or array containing the consecutive values.
For more details about this ability, see the corresponding
API documentation.
The following example test records both types of results for the methods of a mocked DependencyAbc
class, to be used when they are invoked from a UnitUnderTest class.
Lets say the implementation of the class under test goes like this:
public class UnitUnderTest
{
(1)private final DependencyAbc abc = new DependencyAbc();
public void doSomething()
{
(2) int n = abc.intReturningMethod();
for (int i = 0; i < n; i++) {
String s;
try {
(3) s = abc.stringReturningMethod();
}
catch (SomeCheckedException e) {
// somehow handle the exception
}
// do some other stuff
}
}
}
A possible test for the doSomething() method could exercise the case where
SomeCheckedException gets thrown, after an arbitrary number of successful iterations.
Assuming that we want (for whatever reasons) to record a complete set of expectations for the interaction
between these two classes, we might write the test below.
(Often, it's not desirable or important to specify all invocations to mocked methods and - specially -
mocked constructors in a given test. We will address this issue later.)
@Test
public void doSomethingHandlesSomeCheckedException() throws Exception
{
new Expectations() {
DependencyAbc abc;
{
(1) new DependencyAbc();
(2) abc.intReturningMethod(); result = 3;
(3) abc.stringReturningMethod();
returns("str1", "str2");
result = new SomeCheckedException();
}
};
new UnitUnderTest().doSomething();
}
This test records three different expectations.
The first one, represented by the call to the DependencyAbc() constructor, merely accounts for the fact
that this dependency happens to be instantiated in the code under test through the no-args constructor; no result
needs to be specified for such an invocation, except for the occasional exception/error to be thrown (constructors
have void return type, so it makes no sense to record return values for them).
The second expectation specifies that intReturningMethod() will return 3 when called.
The third one specifies a sequence of three consecutive results for stringReturningMethod(), where the
last result happens to be an instance of the desired exception, allowing the test to achieve its goal (note that it
will only pass if the exception is not propagated out).
Whenever an invocation to a mocked non-void method fails to match any recorded expectation, a default
return value needs to be provided.
JMockit will always supply a reasonable return value, according to the declared return type of the method:
0 (zero) for an integral primitive type, false for boolean, an empty
collection or array, or null for reference types (including String and the primitive
wrapper classes).
Mocked constructors and void methods also have a "default result", which is to simply return without
throwing any exception or error.
(Unless the invocation occurring during replay is found to be unexpected, in which case JMockit
automatically throws an AssertionError to cause a test failure.)
We can explicitly override such default results in an expectation block, by declaring indirect input fields.
Such (instance) fields must be annotated with @Input. Here is an example.
@Test
public void someTestMethod()
{
new NonStrictExpectations() {
DependencyAbc mock;
// The names of input fields are merely for documentation.
@Input final int defaultIntReturn = 5;
@Input Socket aSocket;
@Input FileNotFoundException onFileOpen;
{
abc.stringReturningMethod(); returns("str1", "str2");
}
};
new UnitUnderTest().doSomething();
}
In the case of return values, the declared type of the field must be the same as the return type of interest.
Any methods with this return type will return the value assigned to the input field.
This will happen every time the mocked method gets invoked by code under test, provided such invocations are
allowed to occur and there is no recorded expectation matching them.
In the example above, any method belonging to DependencyAbc which returns an int will
always return the value 5; any method returning a Socket will return a socket object
instantiated automatically with the java.net.Socket public no-args constructor (if a custom instance was
needed, we could have it explicitly instantiated and assigned to the field).
Methods and constructors that declare to throw checked exceptions can have one such exception specified as
the default result, by simply declaring an input field of the desired exception type. An exception instance can be
directly instantiated and assigned to the field; if none is, then JMockit will do so automatically using the public
no-args constructor of the exception class.
In the example test, if DependencyAbc has a method or constructor with
java.io.FileNotFoundException in its throws clause, it will cause this exception to be
thrown whenever a non-recorded invocation occurs during the test.
Note that this mechanism depends only on return types and throws clauses, not on
method names or parameters, or even on which mocked class or instance an invocation occurs.
For many methods in production code, we often find that only one value of a certain type is needed for a
given test where the method is called (particularly when it's a reference type, less so when it's a
primitive or String).
This property allows us to write a shorter test, where a "mere" default result is specified instead of having to
record an expectation and deal with full method/constructor signatures.
(Of course, when more precision is required for a given test, a suitable expectation will have to be recorded.)
The following example test is equivalent to its original version shown before, assuming we don't really need to
catch the exception only in the third iteration of the loop inside the tested method; if we do, then recording an
explicit expectation for stringReturningMethod() will be necessary.
@Test
public void doSomethingHandlesSomeCheckedException()
{
new Expectations() {
DependencyAbc abc;
(2) @Input int iterations = 3;
(3) @Input SomeCheckedException onFirstIteration;
};
new UnitUnderTest().doSomething();
}
Previously, we explained that an expectation recorded on a mocked instance, such as
abc.intReturningMethod(); result = 3; would actually match invocations to
DependencyAbc#intReturningMethod() on any instance of the mocked DependencyAbc
class.
In most cases, tested code uses a single instance of a given dependency, so this won't really matter and can
be safely ignored, whether the mocked instance is passed into tested code or created inside it.
But what if we need to verify that invocations occur on a specific instance, between the several/many ones
that happen to be used by code under test?
JMockit actually provides a few different ways to constrain the matching of expectations on specific mocked
instances, as we shall see.
onInstance(m) constraint
We can use the Expectations#onInstance(mockObject) method when recording an expectation, as the next
example shows.
@Test
public void matchOnMockInstance(final Collaborator mock)
{
new Expectations() {{
onInstance(mock).getValue(); result = 12;
}};
// Exercise unit under test with mocked instance passed from the test:
int result = mock.getValue();
assertEquals(12, result);
// If another instance is created inside code under test...
Collaborator another = new Collaborator();
// ...we won't get the recorded result, but the default one:
assertEquals(0, another.getValue());
}
The test above will only pass if the unit under test (here embedded in the test method itself, for brevity)
invokes getValue() on the exact same instance on which the recording invocation was made.
This is typically useful when the unit under test makes calls on two or more different instances of the same type,
and the test wants to verify that each invocation occurred on the proper instance.
To avoid the need to use onInstance(m) on every expectation when testing code which uses multiple
instances of the same type in different ways, JMockit automatically infers the need for "onInstance" matching based
on the set of mocked types in scope.
Specifically, whenever two or more mock fields/parameters of the exact same type are in scope for a given test,
invocations to instance methods made on their (automatically) assigned instances will always match expectations
recorded on those same instances.
Therefore, in such common situations it isn't necessary to explicitly use the onInstance(m) method.
Suppose we need to test code which works with multiple instances of a given class.
If we declare said class to be mocked, then all of its instances will be equally affected: they all become mocked
instances, so that any instance method invoked on them gets handled according to our mocking specifications.
However, what if we need only one (or a few) of those instances to be mocked, while invocations made on
other instances continue to execute the original, "real" implementation?
This is where the @Injectable annotation can help.
(It has other uses too, which we'll address later.)
By simply declaring a mock field or mock parameter as @Injectable, we get an
"exclusive" mocked instance; any other instance of the same mocked type, unless associated with a separate mock
field/parameter, will remain as a regular, non-mocked instance.
Since an injectable mocked instance is used to preserve the original implementation on other instances, it follows
that static methods and constructors are also excluded from being mocked.
After all, a static method is not associated with any instance of the class, while a constructor is
only associated with a newly created (and therefore different) instance.
For an example, lets say we have the following class to be tested.
public static final class ConcatenatingInputStream extends InputStream
{
private final Queue<InputStream> sequentialInputs;
private InputStream currentInput;
public ConcatenatingInputStream(InputStream... sequentialInputs)
{
this.sequentialInputs = new LinkedList<InputStream>(Arrays.asList(sequentialInputs));
currentInput = this.sequentialInputs.poll();
}
@Override
public int read() throws IOException
{
if (currentInput == null) return -1;
int nextByte = currentInput.read();
if (nextByte >= 0) {
return nextByte;
}
currentInput = sequentialInputs.poll();
return read();
}
}
This class could easily be tested without mocking by using ByteArrayInputStream objects for input, but
lets say we want to make sure that the InputStream#read() method is properly invoked on each input
stream passed in the constructor.
The following test will achieve this.
@Test
public void concatenateInputStreams(
@Injectable final InputStream input1, @Injectable final InputStream input2)
throws Exception
{
new Expectations() {{
input1.read(); returns(1, 2, -1);
input2.read(); returns(3, -1);
}};
InputStream concatenatedInput = new ConcatenatingInputStream(input1, input2);
byte[] buf = new byte[3];
concatenatedInput.read(buf);
assertArrayEquals(new byte[] {1, 2, 3}, buf);
}
Note that the use of @Injectable is indeed necessary here, since the class under test
extends the mocked class, and the method called to exercise the former is defined in the latter.
If InputStream was mocked "normally", the read(byte[]) method would always be mocked,
regardless of the instance on which it is called.
(Well, we could still write a test without injectable instances if only the overriding read()
method was called by the test.)
In both the record and verify phases, an invocation to a mocked method or constructor identifies an
expectation.
If the method/constructor has one or more parameters, then a recorded/verified expectation like
doSomething(1, "s", true); will only match an invocation in the replay phase if it has
equal argument values.
For arguments that are regular objects (not primitives or arrays), the equals(Object) method is used for
equality checking.
For parameters of array type, equality checking extends to individual elements; therefore, two different array
instances having the same length in each dimension and equal corresponding elements are considered to be equal.
In a given test, we often don't know exactly what those argument values will be, or they simply aren't essential for
what is being tested.
So, to allow a recorded or verified invocation to match a whole set of replayed invocations with different argument
values, we can specify flexible argument matching constraints instead of actual argument values.
This is done by using withXyz(...) methods and/or anyXyz fields.
The "with" methods and "any" fields are all defined in the mockit.Invocations base class,
which both mockit.Expectations and mockit.Verifications extend.
Therefore, they can be used in expectation as well as verification blocks.
When recording or verifying an expectation, calls to the withXyz(...) methods can occur for any subset
of the arguments passed in the invocation.
They can be freely mixed with regular argument-passing (using literal values, local variables, etc.).
The only requirement is that such calls appear inside the recorded/verified invocation statement, rather than before
it.
It's not possible, for example, to first assign the result of a call to withNotEqual(val) to a local
variable and then use the variable in the invocation statement.
An example test using some of the "with" methods is shown below.
@Test
public void someTestMethod(@NonStrict final DependencyAbc abc)
{
final DataItem item = new DataItem(...);
new Expectations() {{
// Will match "voidMethod(String, List)" invocations with the first argument
// equal to "str" and the second not null.
abc.voidMethod("str", (List<?>) withNotNull());
// Will match invocations to DependencyAbc#stringReturningMethod(DataItem, String)
// with the first argument pointing to "item" and the second one containing "xyz".
abc.stringReturningMethod(withSameInstance(item), withSubstring("xyz"));
}};
new UnitUnderTest().doSomething(item);
new Verifications() {{
// Matches invocations to the specified method with any long-valued argument.
abc.anotherVoidMethod(withAny(1L));
}};
}
There are more "with" methods than shown above. See the API documentation for more details.
Besides the several predefined argument matching constraints available in the API, JMockit allows the user to provide
custom constraints, through the <T> T with(Object) and <T> T with(T, Object>) generic
methods.
The parameter of type Object can be an org.hamcrest.Matcher
object from the Hamcrest library, or a suitable handler object
(see the API documentation for details).
The most common argument matching constraint tends also to be the least restrictive one: to match
invocations with any value for a given parameter (of the proper parameter type, of course).
For such cases we have a whole set of special argument matching fields, one for each primitive type (and the
corresponding wrapper class), one for strings, and a "universal" one of type Object.
The test below demonstrates some uses.
@Test
public void someTestMethod(@NonStrict final DependencyAbc abc)
{
final DataItem item = new DataItem(...);
new Expectations() {{
// Will match "voidMethod(String, List)" invocations where the first argument is
// any string and the second any list.
abc.voidMethod(anyString, (List<?>) any);
}};
new UnitUnderTest().doSomething(item);
new Verifications() {{
// Matches invocations to the specified method with any value of type long or Long.
abc.anotherVoidMethod(anyLong);
}};
}
The same requirement of having calls to "with" methods inside the invocation statement applies in the case of accesses to "any" fields: they must appear at the actual argument positions in the invocation statement, not before. Again, see the API documentation for more details on argument matching fields.
null value to match any object reference
When using at least one argument matching method or field for a given expectation, we can use a "shortcut" to specify
that any object reference should be accepted (for a parameter of reference type).
Simply pass the null value instead of a withAny(x) or any argument matcher.
In particular, this avoids the need to cast the value to the declared parameter type.
However, bear in mind that this behavior is only applicable when at least one explicit argument matcher
(either a "with" method or an "any" field) is used for the expectation.
When passed in an invocation that uses no matchers, the null value will match only the null
reference.
In the previous test, we could therefore have written:
@Test
public void someTestMethod(@NonStrict final DependencyAbc abc)
{
...
new Expectations() {{
abc.voidMethod(anyString, null);
}};
...
}
When one or more argument matchers are used and the null reference must be matched for a given
parameter, the withNull() method should be used.
In conclusion, there are two modes for argument matching: the basic one where no matching constraints are
specified and all arguments must be equal, and the one where matching constraints are specified for some or all
parameters.
The meaning of the null value is different for each mode, which may lead to confusion at times.
For complex invocations where multiple arguments are involved, though, the benefits of being able to use "any" fields
and the null reference should outweigh the additional API complexity.
Occasionally we may need to deal with expectations for "varargs" methods or constructors. It's valid to pass regular values as a varargs argument, and also valid to use the "with"/"any" matchers for such values. However, it's not valid to combine both kinds of value-passing for the same expectation, when targeting a varargs parameter. We need to either use only regular values or only values obtained through argument matchers.
In case we want to match invocations where the varargs parameter receives any number of values (including zero),
we can specify an expectation with the (Object[]) any constraint for the final varargs
parameter.
Probably the best way to understand the exact semantics of varargs matching (since there is no specific API involved) is to look at or experiment with actual tests. This test class demonstrates virtually all possibilities.
So far, we saw that besides an associated method or constructor, an expectation can have invocation results and argument matchers. Given that the unit under test can call the same method or constructor multiple times with different or identical arguments, we need a way to account for all those separate invocations. One way, as already seen, is to simply record one separate expectation for each expected invocation, in the same order as the invocations should be replayed; another is to record two or more consecutive results for a single expectation.
Yet another way is to specify an invocation count constraint for a given expectation.
The mocking API provides three special fields just for that: times,
minTimes, and maxTimes.
These fields belong to the mockit.Invocations class, the non-public base class for
both mockit.Expectations and mockit.Verifications.
Therefore, an invocation count constraint can be specified either when recording or when verifying expectations.
In either case, the method or constructor associated with the expectation will be constrained to receive a number of
invocations that falls in the specified range.
Any invocations less or more than the expected lower or upper limit, respectively, and the test
execution will automatically fail.
Lets see some example tests.
@Test
public void someTestMethod(final DependencyAbc abc)
{
new Expectations() {{
// By default, one invocation is expected, i.e. "times = 1":
new DependencyAbc();
// At least two invocations are expected:
abc.voidMethod(); minTimes = 2;
// 1 to 5 invocations are expected:
abc.stringReturningMethod(); minTimes = 1; maxTimes = 5;
}};
new UnitUnderTest().doSomething();
}
@Test
public void someOtherTestMethod(final DependencyAbc abc)
{
new UnitUnderTest().doSomething();
new Verifications() {{
// Verifies that zero or one invocations occurred, with the specified argument value:
abc.anotherVoidMethod(3); maxTimes = 1;
// Verifies the occurrence of at least one invocation with the specified arguments:
DependencyAbc.someStaticMethod("test", false); // "minTimes = 1" is implied
}};
}
Unlike the result field, each of these three fields can be specified at most once for a given
expectation.
Any non-negative integer value is valid for any of the invocation count constraints.
If times = 0 or maxTimes = 0 is
specified, the first invocation matching the expectation to occur during replay (if any) will cause the test to fail.
For more, see the API documentation.
Expectations recorded inside a new Expectations() {...} block are all strict by default, unless
specified otherwise.
What this means is that the invocations they specify are expected to occur during the replay phase,
and in the same order as they were recorded;
additionally, only these invocations are allowed to occur.
Any unexpected invocations that were not recorded will automatically cause the test to fail.
On the other hand, when we want to record non-strict (or loose) expectations, the
mockit.NonStrictExpectations subclass can be used.
Inside a non-strict expectation block, all invocations to mocked types will be allowed to occur during the
replay phase, not expected.
That is, by default they may or may not occur during replay without causing the test to fail on their own.
Also, they don't have to occur in the same order as they were recorded.
By default, a strict expectation will match exactly one invocation in the replay phase.
That is, the expectation will have an implicit invocation count constraint of 1, as if it was followed
by a times = 1 constraint.
An expectation recorded as non-strict, on the other hand, will by default be allowed to match any number of
invocations in the replay phase.
That is, its implicit invocation count constraint will have a lower limit of 0 and an unbounded upper
limit, as if specified as minTimes = 0.
In either case, however, the implicit invocation count constraint can be overridden by an explicit one (that is, an
explicit assignment to one of the times/minTimes/maxTimes fields).
So, a strict expectation can be made to allow an arbitrary number of invocations, while a non-strict one can be made
to disallow unexpected invocations, when needed.
Note that in the case of strict expectations, all matching invocations occurring during replay are
implicitly verified.
The remaining invocations will be considered unexpected (and fail the test), unless the associated mocked type is not
strict.
So, the use of strict expectations which are verified implicitly precludes the use of verification blocks, which are
used for explicit verification of invocations.
In fact, inside a new Verifications() {...} block only invocations matching recorded non-strict
expectations are permitted, as well as invocations to non-strict mocked types for which no expectation was explicitly
recorded.
To allow mixing strict and non-strict expectations inside a new Expectations() {...} block, we can apply
the mockit.NonStrict annotation to a mock field or parameter.
Any invocation to such a mocked type will be considered as belonging to a non-strict expectation, and all unrecorded
invocations in the replay phase will be allowed (that is, they will never be considered as unexpected, and therefore
will not cause the test to fail).
This is particularly useful to avoid the need to record invocations to constructors, or to any uninteresting methods.
Inside an expectation block, an individual expectation can be explicitly marked as non-strict through a
notStrict() call following the invocation statement.
Most of the time, it will be easier to use a non-strict expectation block or a mock field/parameter annotated as
non-strict, though.
So, how do we choose between strict and non-strict expectations for a given test? There is really no general-purpose answer to this question. It will depend on the particulars of the unit under test, and on personal preferences. Also, keep in mind that a test can mix both kinds of expectations, so there is a lot of flexibility in using them.
It's usually best to think about strictness at the level of individual expectations, not at the level of mocked instances or types. That said, it is also correct to say that a given mocked instance (or mocked type) is strict or non-strict. All it means, really, is that all expectations associated to that particular instance/type have the same strictness. On the other hand, it's perfectly valid to record both strict and non-strict expectations for the same mocked instance or type, in the same test. And when using mock fields declared at the test class level, it's possible that a given mocked instance will be entirely strict in one test and entirely non-strict in another, in the same test class.
To recapitulate, we can specify the lack of strictness in three different ways:
1) that a given recorded expectation in an otherwise strict expectation block should be non-strict, by calling the
notStrict() method;
2) that all expectations for a particular mocked type/instance should be non-strict, by annotating the mock field or
parameter with @NonStrict;
and 3) that all expectations recorded should be non-strict, by using the
NonStrictExpectations class.
On the other hand, there is no explicit way to specify that a given expectation, a mocked type/instance, or a whole
expectation block should be strict.
Recorded expectations are considered strict by default, when we do not specify that they should be
non-strict.
So, for an expectation to be strict, it needs to be recorded inside an expectation block not derived from
NonStrictExpectations, for a mocked type not annotated as
@NonStrict.
The associated mocked type and its instances will then be considered to be strictly verified as a whole, except for
those invocations matching an expectation explicitly recorded as notStrict().
Finally, note that when no expectations are recorded in a test for a given mocked type, it is automatically
assumed to be fully non-strict (as if the mock field/parameter was annotated as
@NonStrict).
When a sequence of consecutive invocations is recorded with strict expectations (the relative order between
invocations is irrelevant with non-strict expectations), the whole sequence is expected to occur exactly
once during the replay phase.
Consider, however, the case where the tested code executes those invocations in a loop (or any kind of iteration).
Assuming that the number of iterations is known in the test, we can still record those expectations with a single
invocation to each method/constructor called inside the loop (that is, without writing a loop or repeating the
expectations inside the expectation block).
The next test demonstrates this feature, using the Expectations(int numberOfIterations) constructor.
@Test
public void recordStrictInvocationsInIteratingBlock(final Collaborator mock)
{
new Expectations(2) {{
mock.setSomething(anyInt);
mock.save();
}};
// In the tested code:
mock.setSomething(123);
mock.save();
mock.setSomething(45);
mock.save();
}
This ability to specify the number of iterations for a group of invocations also applies to non-strict expectations. However, in this case the specified number of iterations is merely used as a multiplier for the upper and lower limits of invocation count constraints (both implicit and explicit ones). Non-strict expectations with no specified invocation count constraint, therefore, are not affected.
Strict expectations are verified implicitly, so there is no point in re-verifying them in a explicit verification block. Non-strict expectations, on the other hand, are usually verified through explicit invocations to mocked types in a verification block. As will be seen later, a recorded non-strict expectation can still be verified implicitly, without the need to write an invocation inside a verification block.
Inside a new Verifications() {...} block we can use the same API that's available in a
new NonStrictExpectations() {...} block, with the exception of the methods and fields used to record
return values and thrown exceptions/errors.
That is, we can freely use the anyXyz fields, the withXyz(...) argument matching methods,
and the times, minTimes, and maxTimes invocation count constraint fields.
An example test follows.
@Test
public void verifyInvocationsExplicitlyAtEndOfTest(final Dependency mock)
{
// Nothing recorded here, but it could be.
// Inside tested code:
Dependency dependency = new Dependency();
dependency.doSomething(123, true, "abc-xyz");
// Verifies that Dependency#doSomething(int, boolean, String) was called at least once,
// with arguments that obey the specified constraints:
new Verifications() {{ mock.doSomething(anyInt, true, withPrefix("abc")); }};
}
Note that, by default, a verification checks that at least one matching invocation occurred during replay.
When we need to verify an exact number of invocations (including 1), the times = n
constraint must be specified.
Mocked instances and mocked types declared as mock fields of the test class or as mock parameters of the test method are immediately available inside verification blocks. However, expectation blocks can also declare local mock fields, which won't be accessible outside the block. In such cases, it's possible to import those mocked instances into a verification block, as the next example shows.
@Test
public void importLocalMockFromPreviousNonStrictExpectationsBlock()
{
new NonStrictExpectations() {
Dependency mock;
{
mock.notifyBeforeSave(); result = true;
}
};
// Inside tested code:
Dependency dependency = new Dependency();
dependency.editABunchMoreStuff();
new Verifications() {
Dependency mock;
{
mock.editABunchMoreStuff();
}
};
}
The mocked types to be imported are identified by the types of the fields declared in the verification, not by the field names. Typically, though, the same field names will be used to avoid confusion. This ability can be useful if for whatever reason mock parameters are not desired, or when capturing internally created instances of mocked types (explained in a later section).
To do this inside a verification block, add a times = 0 assignment right after the
invocation that is expected to not have happened during the replay phase.
If one or more matching invocations did happen, the test will fail.
Regular verification blocks, like the one below, are unordered.
The actual relative order in which aMethod() and anotherMethod() were called during the
replay phase is not verified, but only that each method was executed at least once.
If you want to verify the relative order of invocations, then a
new VerificationsInOrder() {...} block must be used instead.
Inside this block, simply write invocations to one or more mocked types in the order they are expected to have
occurred.
@Test
public void verifyingExpectationsInOrder(final DependencyAbc abc)
{
// Somewhere inside the tested code:
abc.aMethod();
abc.doSomething("blah", 123);
abc.anotherMethod(5);
...
new VerificationsInOrder() {{
// The order of these invocations must be the same as the order
// of occurrence during replay of the matching invocations.
abc.aMethod();
abc.anotherMethod(anyInt);
}};
}
Note that the call abc.doSomething(...) was not verified in the test, so it could have occurred
at any time (or not at all).
Suppose you want to verify that a particular method (or constructor) was called before/after other invocations, but you don't care about the order in which those other invocations occurred. Inside an ordered verification block, this can be achieved by simply calling the unverifiedInvocations() method at the appropriate place(s). The following test demonstrates it.
@Mocked DependencyAbc abc;
@Mocked AnotherDependency xyz;
@Test
public void verifyingTheOrderOfSomeExpectationsRelativeToAllOthers()
{
new UnitUnderTest().doSomething();
new VerificationsInOrder() {{
abc.methodThatNeedsToExecuteFirst();
unverifiedInvocations(); // Invocations not verified must come here...
xyz.method1();
abc.method2();
unverifiedInvocations(); // ... and/or here.
xyz.methodThatNeedsToExecuteLast();
}};
}
The example above is actually quite sophisticated, as it verifies several things:
a) a method that must be called before others; b) a method that must be called after others;
and c) that AnotherDependency#method1() must be called just before DependencyAbc#method2().
In most tests, we will probably only do one of these different kinds of order-related verifications.
But the power is there to make all kinds of complex verifications quite easily.
Another situation not covered by the examples above is one where we want to verify that certain invocations occurred
in a given relative order, while also verifying the other invocations (in any order).
For this, we need to write two separate verification blocks, as illustrated below (where mock is a mock
field of the test class).
@Test
public void verifyFirstAndLastCallsWithOthersInBetweenInAnyOrder()
{
// Invocations that occur while exercising the code under test:
mock.prepare();
mock.setSomethingElse("anotherValue");
mock.setSomething(123);
mock.notifyBeforeSave();
mock.save();
new VerificationsInOrder() {{
mock.prepare(); // first expected call
unverifiedInvocations(); // others at this point
mock.notifyBeforeSave(); // just before last
mock.save(); times = 1; // last expected call
}};
// Unordered verification of the invocations previously left unverified.
// Could be ordered, but then it would be simpler to just include these invocations
// in the previous block, in the place of the "unverifiedInvocations()".
new Verifications() {{
mock.setSomething(123);
mock.setSomethingElse(anyString);
}};
}
Usually, when a test has multiple verification blocks their relative order of execution is important.
In the previous test, for example, if the unordered block came before it would have left no "unverified invocations"
to match a later call to unverifiedInvocations();
the test would still pass (assuming it originally passed) since it's not required that unverified invocations
actually occurred at the called position, but it would not have verified that the unordered group of
invocations occurred between the first and last expected calls.
Sometimes it may be important to have all invocations to the mocked types involved in a test verified.
This is automatically the case when recording strict expectations, since any unexpected invocation causes the test to
fail.
When non-strict expectations are explicitly verified, though, a new FullVerifications() {...} block can
be used to make sure that no invocations are left unverified.
@Test
public void verifyAllInvocations(final Dependency mock)
{
// Code under test included here for easy reference:
mock.setSomething(123);
mock.setSomethingElse("anotherValue");
mock.setSomething(45);
mock.save();
new FullVerifications()
{{
// Verifications here are unordered, so the following invocations could be in any order.
mock.setSomething(anyInt); // verifies two actual invocations
mock.setSomethingElse(anyString);
mock.save(); // if this verification (or any other above) is removed the test will fail
}};
}
Note that if a lower limit (a minimum invocation count constraint) is specified for an otherwise non-strict expectation, then this constraint will always be implicitly verified at the end of the test. Therefore, explicitly verifying such an expectation inside the full verification block is not necessary.
So, we have seen how to do unordered verifications with Verifications,
ordered verifications with VerificationsInOrder, and full verifications
with FullVerifications.
But what about full ordered verifications? Easy enough:
@Test
public void verifyAllInvocationsInOrder(final Dependency mock)
{
// Code under test included here for easy reference:
mock.setSomething(123);
mock.setSomethingElse("anotherValue");
mock.setSomething(45);
mock.save();
new FullVerificationsInOrder()
{{
mock.setSomething(anyInt);
mock.setSomethingElse(anyString);
mock.setSomething(anyInt);
mock.save();
}};
}
Notice there is a not so obvious difference in semantics, though.
In the verifyAllInvocations test above, we were able to match two separate
mock.setSomething(...) invocations with a single invocation in the verification block.
In the verifyAllInvocationsInOrder test, however, we had to write two separate
invocations to that method inside the block, in the proper order with respect to other invocations.
You may now be thinking that writing a FullVerificationsInOrder block ends up being
the same as writing an Expectations block where all expectations are strict.
So, have we come full circle? Almost, but not quite.
For non-strict expectations, the default invocation count constraint corresponds to a
minTimes = 1 assignment, which leaves room for multiple invocations to the
same method or constructor in the replay phase.
So, in the above test for example, if the setSomethingElse(...) method was invoked
a second time during the replay phase, the test would still pass (provided the second invocation
occurred in the expected order, as specified inside the verification block).
By default, all invocations to all mocked instances/types in effect for a
given test must be verified explicitly when using a new FullVerifications() {} or
new FullVerificationsInOrder() {} block.
Now, what if we have a test with two (or more) mocked types but we only want to fully verify
invocations to one of them (or to any subset of mocked types when more than two)?
The answer is to use the FullVerifications(Object... mockedTypesAndInstancesToVerify)
constructor, where only the given mocked instances and mocked types (ie, class objects/literals) are considered.
The following test provides an example.
@Test
public void verifyAllInvocationsToOnlyOneOfTwoMockedTypes(Dependency mock1, AnotherDependency mock2)
{
// Inside code under test:
mock1.prepare();
mock1.setSomething(123);
mock2.doSomething();
mock1.editABunchMoreStuff();
mock1.save();
new FullVerifications(mock1)
{{
mock1.prepare();
mock1.setSomething(anyInt);
mock1.editABunchMoreStuff();
mock1.save(); times = 1;
}};
}
In the test above, the mock2.doSomething() invocation is never verified.
It's possible to restrict verification only to the methods (and constructors) of a single class,
by passing its class literal in the FullVerifications(...) or FullVerificationsInOrder(...)
constructor.
For example, the new FullVerificationsInOrder(AnotherDependency.class) { ... } block would only make
sure that all invocations to the mocked AnotherDependency class were verified.
To verify that no invocations at all occurred on the non-strict mocked types/instances used in a test, add
an empty full verification block to it.
As always, note that any expectations that were recorded as expected through an specified
times/minTimes constraint are verified implicitly and therefore disregarded by the full verification
block; in such a case the empty verification block will verify that no other invocations occurred.
Additionally, if any expectations were verified in a previous verification block in the same test, they are
also disregarded by the full verification block.
If the test uses two or more mocked types/instances and you want to verify that no invocations occurred for some of them, specify the desired mocked types and/or instances in the constructor to the empty verification block. An example test follows.
@Test
public void verifyNoInvocationsOnOneOfTwoMockedDependenciesBeyondThoseRecordedAsExpected(
final Dependency mock1, final AnotherDependency mock2)
{
new NonStrictExpectations()
{{
// These two are recorded as expected:
mock1.setSomething(anyInt); minTimes = 1;
mock2.doSomething(); times = 1;
}};
// Inside code under test:
mock1.prepare();
mock1.setSomething(1);
mock1.setSomething(2);
mock1.save();
mock2.doSomething();
// Will verify that no invocations other than to "doSomething()" occurred on mock2:
new FullVerifications(mock2) {};
}
A full verification block (ordered or not) also allows us to verify that certain methods and/or constructors never
get invoked, without having to specify each one of them with a corresponding times = 0
assignment.
The following test provides an example.
@Test
public void readOnlyOperation(final Dependency mock)
{
new NonStrictExpectations()
{{
mock.getData(); result = "test data";
}};
// Code under test:
String data = mock.getData();
// mock.save() should not be called here
...
new FullVerifications()
{{
mock.getData(); minTimes = 0; // calls to getData are allowed
}};
}
If a call to any method (or constructor) of the Dependency class occurs during the
replay phase, except for the ones explicitly verified in the verification block
(Dependency#getData() in this case), then the test above will fail.
On the other hand, it may be easier to use strict expectations in such cases, without any verification block at all.
There is one last thing about verification blocks we need to examine: the ability to easily verify invocations that occur inside loops, for an specified number of iterations of the loop.
@Test
public void verifyAllInvocations(final Dependency mock)
{
int numberOfIterations = 3;
// Code under test included here for easy reference:
for (int i = 0; i < numberOfIterations; i++) {
DataItem data = getData(i);
mock.setData(data);
mock.save();
}
new Verifications(numberOfIterations)
{{
mock.setData((DataItem) withNotNull());
mock.save();
}};
new VerificationsInOrder(numberOfIterations)
{{
mock.setData((DataItem) withNotNull());
mock.save();
}};
}
The use of two verification blocks above is just to explain the different semantics between
ordered and unordered iterating verification blocks.
In the first block, each verified invocation will have to match at least three invocations to the
same method in the replay phase, because this was the number of iterations passed in the constructor.
For an unordered iterating block, the specified number of iterations is effectively multiplied by
the lower and upper invocation count limits; this happens even if an explicit constraint is
specified inside the block, such as a minTimes = 1; maxTimes = 4;
pair of assignments, which in this particular example would be turned into
minTimes = 3; maxTimes = 12;.
In the second block, on the other hand, invocation count constraints are not affected.
Instead, the resulting effect is equivalent to "unrolling the loop", as if the whole sequence of
verified invocations inside the block was duplicated for each iteration.
The semantics for an iterating FullVerifications block is the same as for a regular
Verifications block.
The same applies for an iterating FullVerificationsInOrder block, with respect to a
VerificationsInOrder block.
We have seen how to record results for invocations through assignments to the
result field or calls to the returns(...) methods.
We have also seen how to match invocation arguments flexibly with the withXyz(...)
group of methods and the various anyXyz fields.
But what if a test needs to decide the result of a recorded invocation based on the arguments it
will receive at replay time?
We can do it through a mockit.Delegate instance, as exemplified below.
@Test
public void someTestMethod()
{
new Expectations()
{
@NonStrict DependencyAbc abc;
{
abc.intReturningMethod(anyInt, null);
result = new Delegate()
{
// The name of this method can actually be anything.
int intReturningMethod(int i, String s)
{
assertTrue(i > 0);
assertEqual(i == 1 ? "one" : "other", s);
return i + 1;
}
};
}
};
new UnitUnderTest().doSomething();
}
The Delegate interface is empty, being used simply to tell JMockit that actual
invocations at replay time should be delegated to the corresponding methods in the delegate object.
A corresponding method in the delegate implementation must have parameters matching the method
in the mocked type for which an invocation is being recorded.
The name of this delegate method can be different though, provided it is the only one
defined in the delegate implementation class.
If the class has two or more methods (with any modifiers), then one of them will have
to match both the name and the parameters of the corresponding recorded method.
Note that the return type of a delegate method does not have to be exactly the same, since it's
not part of the method signature. It should be compatible, though, otherwise a
ClassCastException is likely.
Note also that this can de done for non-public methods and even for
static, final, and native mocked methods.
The following example test shows a constructor invocation being delegated in a reusable
Delegate class, which saves an argument value for later verification in the test.
@Test
public void anotherTestMethod()
{
final ConstructorDelegate delegate = new ConstructorDelegate();
new Expectations()
{
Collaborator mock;
{
new Collaborator(anyInt); result = delegate;
}
};
new Collaborator(4);
assertTrue(delegate.capturedArgument > 0);
}
static class ConstructorDelegate implements Delegate
{
int capturedArgument;
void $init(int i) { capturedArgument = i; }
}
Constructors are also handled by delegate methods, except that such methods must be named "$init".
Delegate implementations can be used to validate invocation arguments, but they are limited
to expectation blocks.
Besides, the main point of delegate methods is to specify invocation results (values to return or exceptions
to throw) at replay time, based on the arguments received.
If the actual need is to validate the arguments passed at replay time in each invocation matching
an expectation, the forEachInvocation field should be used instead.
Such validations can be specified not only in expectation blocks, but also in verification blocks.
For example, consider the following test:
@Test
public void verifyExpectationWithArgumentValidatorForEachInvocation(final Collaborator mock)
{
// Inside tested code:
new Collaborator().doSomething(true, new int[2], "test");
new Verifications() {{
mock.doSomething(anyBoolean, null, null);
forEachInvocation = new Object()
{
void validate(Boolean b, int[] i, String s)
{
assertTrue(b);
assertEquals(2, i.length);
assertEquals("test", s);
}
};
}};
}
In this test, all invocations to the Collaborator#doSomething method that occur during the replay phase
and that match the verified expectation will be validated by a call to the specified
validate method.
Each such call will be made with the same arguments that the verified method/constructor received at replay time.
In this particular example, the verified expectation matches invocations with any arguments, but
more strict argument matchers could have been used.
Differently from Delegate implementations, the object assigned to the
forEachInvocation field can be of any type.
The implementation class, however, should define exactly one non-private method of any name, with the
same number of parameters as the validated method/constructor (any number of additional private methods
is allowed).
The types of corresponding parameters don't have to be exactly the same, but they must be
compatible in order to avoid the potential for ClassCastException's.
Optionally, a first parameter of type mockit.Invocation can be declared in the
validation method, which should still have the remaining parameters. The semantics in this case
are the same as in the case of a Delegate method with that same special parameter.
Normally, behavior-based tests for a given unit are written against the
public/protected/default interface of the unit's dependencies.
Sometimes, however, the method being tested may call private methods defined in the
same class, and accounting for the behavior of those methods in the test may be undesirable
(perhaps because it is too complex or simply not important for the test).
A different situation arises when a test wants to verify not only the behavior, but also the state of the unit under test after it is exercised, and the relevant state is stored in non-accessible fields. Some tests may also need to set some necessary state in non-accessible fields of the unit under test before it is exercised.
A third kind of situation would be the eventual need to instantiate non-accessible classes from a given test. Such a need should be rare, though.
To handle these needs (rare though they may be) the Expectations class provides a
set of Reflection-based utility methods that allow a test to invoke non-accessible methods on a
given object or class, to instantiate objects through non-accessible constructors, and to get or
set the values of fields in given objects or classes.
The example test below showcases some of these utility methods.
@Test
public void someTestMethod()
{
final UnitUnderTest tested = new UnitUnderTest();
new Expectations()
{
@NonStrict DependencyAbc abc;
{
// Defines some necessary state on the unit under test:
setField(tested, "someIntField", 123);
// Expectations recorded (even if the invocations are done through Reflection):
newInstance("some.package.AnotherDependency", true, "test"); maxTimes = 1;
invoke(tested, "intReturningMethod", 45, ""); result = 1;
// other expectations recorded...
}
};
tested.doSomething();
String result = Deencapsulation.getField(tested, "result");
assertEquals("expected result", result);
}
The utility methods mentioned above are actually defined in the Invocations base class,
and therefore they are also available to Verifications subclasses.
This allows invocations to private methods and constructors to be verified in a verification block, just like they
can be recorded in an expectation block.
The mockit.Deencapsulation class used at the end of the test is a separate utility
class which contains those same Reflection-based utilities.
It's a more generally useful class, since it can be called from any place in test code.
Its methods are all static, so they can be statically imported for easier access.
By default, all methods and constructors which can be called on a mocked type and its super-types
(except for java.lang.Object) get mocked.
This is appropriate for most tests, but in some situations we might need to select only certain methods or
constructors to be mocked; or we might prefer to exclude certain methods/constructors from being mocked.
Methods/constructors not mocked in an otherwise mocked type will execute normally when called.
Methods and constructors to be mocked can be explicitly specified through the
@Mocked(methods = {"filter1", "filter2", ...})
annotation attribute.
Each filter value is composed of an optional regular expression (java.util.regex)
that matches method names, followed by an also optional parenthesized list of parameter type names.
The following example test shows several ways to use these mocking filters.
public class MyTestClass
{
@Mocked("nanoTime") final System system = null;
@Mocked("print") final JComponent component = new JButton();
@Test
public void staticPartialMocking(@Mocked(methods = "()", inverse = true) final Graphics graphics)
{
...
new Expectations() {
@Mocked({"(int)", "doInternal()", "[gs]etValue", "complexOperation(Object)"})
Collaborator mock;
{
graphics.setClip(0, 0, 80, 60);
graphics.translate(-15, -12);
component.print(graphics);
mock.getValue();
}
};
...
}
}
For convenience, the @Mocked annotation defines the default
value attribute as a synonym for the methods attribute.
This is what allows us to write @Mocked("nanoTime"), as shown above.
The inverse attribute, which is false by default, inverts the meaning of the specified
filters.
For example, while @Mocked("nanoTime") or
@Mocked(methods = "nanoTime", inverse = false) select only the
System#nanoTime() method to be mocked, the inverse specification
@Mocked(methods = "nanoTime", inverse = true) select
it as the only method not mocked in the java.lang.System class.
To select constructors, we leave the first part of the filter (which corresponds to method names) empty and specify the parameter type names between parentheses. Commas are used to separate parameters, when more than one. A parameter type name can be fully qualified or a unique suffix of the full name. In practice, this means that it's almost never necessary to specify package names for a reference type.
Specifying parameter types in a filter for a method is also perfectly valid, but usually unnecessary. It might only be required when the method is overloaded.
Finally, notice that when the mocked type is a class, a mocking filter will match methods/constructors defined
anywhere in the class hierarchy, from the mocked class up to (but not including) Object.
Static partial mocking has the inconvenience that we need to explicitly specify the methods/constructors to be mocked or not mocked, and do so inside strings instead of in Java code. In short, it entails extra work and is not "refactoring friendly".
An alternative that avoids both problems is to let JMockit figure out whether to execute the real implementation of methods/constructors during the replay phase, based on which invocations were recorded and which were not. We describe this feature as dynamic partial mocking, since the decision of what gets mocked is made at runtime, as invocations to mocked types get matched against recorded expectations. The following example tests will demonstrate it.
public final class DynamicPartialMockingTest
{
static class Collaborator
{
private final int value;
Collaborator() { value = -1; }
Collaborator(int value) { this.value = value; }
int getValue() { return value; }
final boolean simpleOperation(int a, String b, Date c) { return true; }
static void doSomething(boolean b, String s) { throw new IllegalStateException(); }
}
@Test
public void dynamicallyMockAClass()
{
new Expectations(Collaborator.class) {{
new Collaborator().getValue(); result = 123;
}};
// Mocked:
Collaborator collaborator = new Collaborator();
assertEquals(123, collaborator.getValue());
// Not mocked:
assertTrue(collaborator.simpleOperation(1, "b", null));
assertEquals(45, new Collaborator(45).value);
}
@Test
public void dynamicallyMockAnInstance()
{
final Collaborator collaborator = new Collaborator(2);
new NonStrictExpectations(collaborator) {{
collaborator.simpleOperation(1, "", null); result = false;
Collaborator.doSomething(anyBoolean, "test");
}};
// Mocked:
assertFalse(collaborator.simpleOperation(1, "", null));
Collaborator.doSomething(true, null);
// Not mocked:
assertEquals(2, collaborator.getValue());
assertEquals(45, new Collaborator(45).value);
assertEquals(-1, new Collaborator().value);
}
}
As shown above, the Expectations(Object...) and
NonStrictExpectations(Object...) constructors accept one or more classes or objects to
be partially mocked.
If the Class object for a given class is passed, the methods and constructors defined in that class are
considered for mocking, but not the methods and constructors of its super-classes.
If an instance of a given class is passed, then all methods defined in the whole class hierarchy, from the
concrete class of the given instance up to (but not including) Object, are considered for mocking;
the constructors of these classes, however, are not (since an instance was already created).
Notice that in these two example tests there is no mock field or mock parameter. Dynamic mocking effectively provides yet another way to specify mocked types. It also lets us turn objects stored in local variables into mocked instances. Such objects can be created with any amount of state in internal instance fields; they will keep that state when mocked.
As we saw, dynamic mocking is based on a simple rule for deciding whether an invocation at replay time should execute
the real implementation or not: if it matches a recorded expectation, it gets mocked; otherwise, the real
implementation gets executed.
Although simple, this rule can produce surprising results, in particular when strict expectations are
recorded.
For example, if you record a strict expectation on a dynamically mocked object with a maximum invocation count of
n (either the default of 1 or a value specified with times or
maxTimes), then only the first n invocations during replay will match the expectation;
the next invocation, if it occurs, will cause the real method implementation to be executed, instead of causing the
test to fail with an "unexpected invocation" error.
It's also valid to pass the mocked instances automatically created for mock fields or parameters into those
expectation block constructors.
In this case, the declaration of such dynamically mocked mock fields/parameters can make use of the
Mocked annotation and any of its attributes.
We could even combine static and dynamic partial mocking for the same mocked class, although that wouldn't probably
be of much use.
When using complex APIs where functionality is distributed through many different objects, it is not uncommon to see
chained invocations of the form obj1.getObj2(...).getYetAnotherObj().doSomething(...).
In such cases it may be necessary to mock all objects/classes in the chain, starting with obj1.
The @Cascading annotation provides this ability.
Just like @Mocked, it can be applied to mock fields and mock parameters.
Similarly to @NonStrict and @Injectable, the use of
@Cascading on a mock field or test method parameter also implies that the type is
mocked (this doesn't preclude use of @Mocked on the same field/parameter, however).
The following test shows a basic example, where the cascading mocked type is used in expectation
and verification blocks. The test involves use of the java.net and java.nio APIs.
@Test
public void recordAndVerifyExpectationsOnCascadedMocks(@Cascading final Socket mock)
throws Exception
{
new NonStrictExpectations() {
InetSocketAddress unused;
{
mock.getChannel().isConnected(); result = false;
}
};
// Inside production code:
Socket s = new Socket(...);
...
if (!s.getChannel().isConnected()) {
SocketAddress sa = new InetSocketAddress("remoteHost", 123);
s.getChannel().connect(sa);
}
...
new Verifications() {{
mock.getChannel().connect((SocketAddress) withNotNull());
}};
}
In the test above, since the Socket class was mocked with cascading, any calls to
methods like getChannel() will return a cascaded mock object whenever they
occur during the test. The cascaded mock will allow further cascading, so a null
reference will never be obtained from methods which return object references (except for return
types Object or String which will return null, or
collection types which will return a non-mocked empty collection).
By default, a new cascaded mock is created for each unique chain of method calls, starting from a
given cascading type. If necessary, this default mock can be replaced with a regular mock,
introduced though a mock field or parameter. To do so, assign the desired mock instance to the
result field, right after the method invocation chain of interest.
Our discussion of this feature will be based on the (contrived) code below. Realistic examples can be found in the Timing Framework and Animated Transitions sample test suites, available with the full JMockit distribution.
public interface Service { int doSomething(); }
final class ServiceImpl implements Service { public int doSomething() { return 1; } }
public final class TestedUnit
{
private final Service service1 = new ServiceImpl();
private final Service service2 = new Service() { public int doSomething() { return 2; } };
Observable observable;
public int businessOperation(final boolean b)
{
new Callable() { // Callable is a parameterized interface from java.util.concurrent
public Object call() { throw new IllegalStateException(); }
}.call();
observable = new Observable() {{ // Observable is a concrete class from java.util
if (b) {
throw new IllegalArgumentException();
}
}};
return service1.doSomething() + service2.doSomething();
}
}
The method we want to test, businessOperation(boolean), creates several new instances of classes that
implement public abstractions.
Most of these implementations are defined through anonymous inner classes, which are completely inaccessible (except
for the use of Reflection) from client code.
This kind of situation will probably not occur often in real projects, though. Still, we can write a test that captures such class definitions and instantiations as they happen during test execution, automatically mocking the implementation classes as they are loaded by the JVM. (As a matter of fact, classes that have been loaded previously will also get mocked for the duration of a given test, transparently and as needed.) The next test shows how it's done.
public final class UnitTest
{
@Capturing Service service;
@Test
public void captureAllInternallyCreatedInstances(@Capturing(maxInstances = 1) final Callable<?> callable)
throws Exception
{
Service initialMockService = service;
new NonStrictExpectations() {
@Capturing(maxInstances = 1) Observable observable;
{
service.doSomething(); returns(3, 4);
}
};
TestedUnit unit = new TestedUnit();
int result = unit.businessOperation(true);
assertNotNull(unit.observable);
assertNotSame(initialMockService, service);
assertEquals(7, result);
new Verifications() {{ callable.call(); }};
}
}
Note that we used all three possible scopes for mocked types: a mock field of the test class, a mock parameter of the
test method, and a local mock field of the expectation block.
In all three cases the mocked type is either an interface or a non-final class, but instead of using
"@Mocked" we used the special annotation
"@Capturing".
This annotation has an optional attribute which takes an int value specifying the maximum
number of new instances of the mocked type that should be "captured" during the test; if not specified, there is no
limit.
Any (future) instantiation of a class that is assignable to the declared mocked type will be affected.
For a non-final mock field, each captured instance will be immediately assigned to the field, up to the
specified maximum number of instances.
If any more instantiations occur they won't be assigned to the field, even though the classes to which such instances
belong will still get mocked.
However, if there is a second capturing field of the same mocked type, then those extra instances will get assigned
to it up to the its maximum number of instances to capture.
So, once a mocked type is declared to be captured, all implementation classes will get mocked for
the test, no matter how many new instances are captured.
If control over which implementation classes should get captured or not is needed, we can use the
classNames and inverse attributes of
@Capturing; see the API documentation for details.
Typically, a test class will exercise a single tested class.
JMockit can help by automatically instantiating this class, and optionally injecting the relevant mocked
dependencies.
This is what the @Tested annotation is for.
A non-final instance field annotated as such in the test class will be considered for automatic
instantiation and injection, just before the execution of a test method.
If at this time the field still holds the null reference, JMockit will try to create an instance using
a suitable constructor of the tested class, and make sure its internal dependencies get properly injected (when
applicable).
If the field has already been initialized (not null), then nothing will be done.
For injection to be performed, the test class must also define one or more
@Injectable fields.
Mock fields annotated only with @Mocked, @NonStrict,
etc. are not considered for injection.
On the other hand, not all injectable fields need to be mock fields; fields of primitive or array types can
also be annotated as @Injectable, and will be equally considered when injection is
performed.
The following example test class will demonstrate.
public class SomeTest
{
@Tested CodeUnderTest tested;
@Injectable Dependency dep1;
@Injectable AnotherDependency dep2;
@Injectable int someIntegralProperty = 123;
@Test
public void someTestMethod()
{
// Record expectations on mocked types, if needed.
tested.exerciseCodeUnderTest();
// Verify expectations on mocked types, if required.
}
}
Note that a non-mockable injectable field must have a value explicitly assigned to it, otherwise the default value would be used.
Two forms of injection are supported: constructor injection and field injection.
In the first case, the tested class must have a single public constructor if it's a public
class; a non-public tested class is also accepted, provided it has a single package-private
constructor.
Once the tested class is initialized with this single constructor, its non-final instance fields are
considered for injection.
For each such field to be injected, an injectable field of the same type is searched in the test class.
If only one is found, its current value is read and then stored in the injected field.
If there is more than one, the injected field name is used to select between the injectable fields of same type.
The simplest form of test code reuse with JMockit is the declaration of mock fields at the test class level. As the next example shows, the objects that are created and assigned to such fields (by JMockit or explicit test code) can be used in any number of test methods. The complete source code for this example can be found under jmockit/samples/LoginService.
public final class LoginServiceTest
{
@Tested LoginService service;
@Mocked UserAccount account;
@Before
public void init()
{
new NonStrictExpectations() {{ UserAccount.find("john"); result = account; }};
}
@Test
public void setAccountToLoggedInWhenPasswordMatches() throws Exception
{
willMatchPassword(true);
service.login("john", "password");
new Verifications() {{ account.setLoggedIn(true); }};
}
private void willMatchPassword(final boolean match)
{
new NonStrictExpectations() {{ account.passwordMatches(anyString); result = match; }};
}
@Test
public void notSetAccountLoggedInIfPasswordDoesNotMatch() throws Exception
{
willMatchPassword(false);
service.login("john", "password");
new Verifications() {{ account.setLoggedIn(true); times = 0; }};
}
// other tests that use the "account" mock field
}
The tests in this example test class exercise the LoginService#login(String accountId, String password)
method (our unit under test).
This method first attempts to look up an existing user account from the given login name ("accountId", which is
expected to be unique among all accounts).
Since several different tests are needed to fully exercise this unit, a non-strict invocation to the
UserAccount#find(String accountId) method is recorded for all tests in the class, with an specific login
name ("john") and the mocked account as the value to be returned.
Remember, any given test can use multiple expectation and/or verification blocks.
Such blocks can also be written inside shared "before" and "after" methods, respectively.
Another form or reuse exemplified above is shown by the willMatchPassword(boolean) method, which
contains another reusable expectation block.
In this case, an invocation to the UserAccount#passwordMatches(String) method is recorded for any
password value, with the resulting return value provided as a parameter to the reusable method.
Yet another form of reuse for expectation and verification blocks is to create named subclasses instead of anonymous
ones.
For example, instead of having the willMatchPassword(boolean) method we could have a reusable inner
class:
final class PasswordMatching extends NonStrictExpectations
{
PasswordMatching(boolean match)
{
account.passwordMatches(anyString); result = match;
}
}
@Test
public void setAccountToLoggedInWhenPasswordMatches() throws Exception
{
new PasswordMatching(true);
...
}
It's important that such classes be declared to be final, unless they are intended to
be used as base classes for further extension.
Such non-final base classes must have names ending in "Expectations" or
"Verifications", however; otherwise they won't be recognized as such by JMockit.
Finally, reusable Expectations/Verifications subclasses can also be top-level classes,
allowing them to be reused in any number of test classes.