Constraints
When defining expectations upon your mock objects, jMock forces you to be explicit about the argument values that will be passed to the expected methods. Expected argument values are defined using "constraints". jMock provides a set of constraints that are suitable for almost all tests. These constraints can be combined to tighten or loosen the specification if necessary. The set of constraints is extensible1 so you can write new constraints to cover unusual testing scenarios.
Constraints are specified by calling "syntactic sugar" methods of the MockObjectTestClass. The following constraints are defined by jMock:
Basic Constraints
Object Equality
The most commonly used constraint is eq
, which specifies that the received
argument must be equal to a given value. The code below, for example, specifies that the
method "m" must be called with one argument of value 1.
mock.expects(once()).method("m").with( eq(1) );
The eq
constraint uses the equals
method of the expected value
to compare the expected and actual values for equality. Null values are checked beforehand,
so it is safe to specify eq(null)
or apply the constraint to a null actual value.
The eq
constraint is overridden for all primitive types; primitive values are
boxed into objects that are then compared using the equals
method.
Arrays are treated as a special case: two arrays are considered equal by eq
if they are the
same size and all their elements are considered equal by eq
.
Numeric Equality with Error Margin
An overloaded version of the eq
constraint specifies floating point values
as equal to another value with some margin of error to account for rounding error.
The following code specifies that the method "m" will be called with one argument
of value 1 plus or minus 0.002.
mock.expects(once()).method("m").with( eq(1, 0.002) );
Object Identity
The same
constraint specifies that the actual value of the argument must be
the same object as the expected value. This is a tighter constraint than eq
,
but is usually what you want for arguments that pass references to behavioural objects.
The following code specifies that method "m" will be called with one argument that refers
to the same object as expected.
Object expected = new Object(); mock.expects(once()).method("m").with( same(expected) );
As a rule of thumb, use eq
for value objects and same
for
behavioural objects.
Instance of a Type
The isA
constraint specifies that the actual argument must be an instance of
the given type. The following code specifies that method "m" must be called with an argument
that is an ActionEvent.
mock.expects(once()).method("m").with( isA(ActionEvent.class) );
String Contains a Substring
The stringContains
constraint specifies that the expected argument must be
a string that contains the given substring. The following code specifies that method
"m" must be called with an argument that is a string containing the text "hello".
mock.expects(once()).method("m").with( stringContains("hello") );
The stringContains
constraint is especially useful for testing string
contents but isolating tests from the exact details of punctuation and formatting.
For example, the code above would accept any of the following argument values:
"hello world"; "hello, world"; "hello!"; and so on.
Null or Not Null
The constraints NULL
and NOT_NULL
are specify that an argument
is null or is not null, respectively. These are constants, not methods. The following code
specifies that method "m" must be called with two arguments, the first must be null and the
second must not be null.
mock.expects(once()).method("m").with( NULL, NOT_NULL );
Anything
The ANYTHING
constraint specifies that any value is allowed. This is useful for
ignoring arguments that are not germane to the scenario being tested. Judicious use of the
ANYTHING
constraint can ensure that your tests are flexible and do not require constant maintenance
when tested code changes. The following code specifies that the method "m" must be called with
two arguments, the first of which is equal to 1 and the second of which is ignored in this test.
mock.expects(once()).method("m").with( eq(1), ANYTHING );
Combining Constraints
Constraints can be composed to create a tighter or looser specification. Composite constraints are themselves constraints and can therefore be further composed.
Not — Logical Negation
The not
constraint specifies that the actual argument must not meet
a given constraint. The following code specifies that the method "m" must be called with an
argument that is not equal to 1.
mock.expects(once()).method("m").with( not(eq(1)) );
And — Logical Conjunction
The and
constraint specifies that the actual argument must meet both
of two constraints given as arguments. The following code specifies that the method "m" must
be called with a string that contains the text "hello" and the text "world".
mock.expects(once()).method("m").with( and(stringContains("hello"), stringContains("world")) );
Or — Logical Disjunction
The or
constraint specifies that the actual argument must meet either
of two constraints given as arguments. The following code specifies that the method "m" must
be called with a string that contains the text "hello" or the text "howdy".
mock.expects(once()).method("m").with( or(stringContains("hello"), stringContains("howdy")) );
More Constraints
That covers all of the constraints provided by jMock. Most of your tests will only need the basic constraints. Sometimes you may need to define constraints by composing existing constraints. Occasionally, however, you might find that no existing constraint exactly meets the need of your test. In these cases, you will have to extend jMock's set of constraints by writing a custom constraint1.