mockit.Expectations Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmockit Show documentation
Show all versions of jmockit Show documentation
JMockit is a Java toolkit for developer (unit/integration) testing.
It contains mocking APIs and other tools, supporting both JUnit and TestNG.
The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested
in isolation from selected dependencies.
/*
* Copyright (c) 2006-2011 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit;
import java.util.*;
import mockit.internal.expectations.*;
/**
* Base class whose subclasses are defined in test code, and whose instances define a set of expected and/or
* allowed method/constructor invocations on the mocked types declared through one or more mock fields
* and/or mock parameters.
* A (local) mock field is any field declared in a subclass which is either non-private or annotated with
* {@link Mocked}.
*
* Typically, this class is used by extending it with anonymous inner classes (named as expectation
* blocks) inside test methods, which record expectations on mocked types by calling instance methods on mock
* fields/parameters, static methods on mocked classes, and/or constructors of mocked classes.
* Arguments passed in such calls are later matched to the actual arguments passed from the code under test.
*
* Any mock fields declared within an expectation block will only be accessible for invocations inside this particular
* block.
* An alternative is to declare mock fields of the test class itself, so that all of its test methods can share
* the same mock fields. Such fields need to be annotated as {@code @Mocked}, though.
*
* There are several API fields and methods which the expectation block can use for recording desired return values and
* exceptions/errors to be thrown (see {@link #result}), and for specifying argument matching constraints (see
* {@link #anyString}).
*
* Individual expectations are defined during the record phase, and later exercised during the
* replay phase of the test.
* At the end of the test, the test runner will automatically assert that all expected invocations actually
* occurred during the replay phase. (An expectation block may also record expectations that are merely
* allowed to occur, and as such are not implicitly verified at the end of the test.)
*
* Additional features and details:
*
* -
* A mock field can be of any non-primitive type, including interfaces, abstract classes, and concrete
* classes (even {@code final} classes).
* An instance will be automatically created when the subclass gets instantiated, unless the field is {@code final}
* (in which case, the test code itself will have the responsibility of obtaining an appropriate instance).
* This mocked instance can then be used inside the expectation block for the recording of expectations on instance
* methods; static methods and constructors belonging to the mocked class or its
* super-classes are also mocked, and can also have expectations recorded on them.
*
* -
* Unless specified otherwise, all expectations defined inside an {@code Expectations} immediate subclass will be
* strict, meaning that the recorded invocations are expected to occur in the same order during the
* replay phase, and that non-recorded invocations are not allowed.
* This default behavior can be overridden for individual expectations through the {@link #notStrict()} method, and for
* whole mocked types through the {@link NonStrict} annotation.
*
* -
* There is a set of API methods that allow the {@linkplain #newInstance(String, Class[], Object...) instantiation of
* non-accessible (to the test) classes}, the {@linkplain #invoke(Object, String, Object...) invocation of
* non-accessible methods}, and the {@linkplain #setField(Object, String, Object) setting of non-accessible fields}.
* Most tests shouldn't need these facilities, though.
*
* -
* A set of special API fields provides the ability to specify how many {@linkplain #times times} a recorded invocation
* is expected and allowed to occur during replay, the {@linkplain #minTimes minimum number of times} it's
* expected, or the {@linkplain #maxTimes maximum number of times} it will be allowed to occur.
*
* -
* By default, the exact instance on which instance method invocations occur during the replay phase is not
* verified to be the same as the instance used when recording the corresponding expectation.
* If such verification is needed, the {@link #onInstance(Object)} method should be used.
*
* -
* There are additional constructors which provide other features:
* {@linkplain #Expectations(Object...) dynamic partial mocking}, and
* {@linkplain #Expectations(int, Object...) iterated invocations}.
*
*
* In the Tutorial
*
* @see #Expectations()
*/
public abstract class Expectations extends Invocations
{
private final RecordAndReplayExecution execution;
/**
* A value assigned to this field will be taken as the result for the current expectation.
*
* If the value is of type {@link Throwable} then it will be thrown when a matching invocation occurs in the
* replay phase.
* Otherwise, it's assumed to be a return value for a non-void method, and will be returned at replay time
* from a matching invocation.
*
* Attempting to return a value that is incompatible with the method return type will cause a
* {@code ClassCastException} to be thrown at replay time.
* If, however, the recorded invocation is to a constructor or {@code void} method, then a matching invocation during
* replay will be allowed, with the specified return value simply being ignored.
*
* If the current expectation is for a method which actually returns an exception or error (as opposed to
* throwing one), then the {@link #returns(Object)} method should be used instead.
*
* If the value assigned to the field is an array or of a type assignable to {@link Iterable} or to {@link Iterator},
* then it is taken as a sequence of consecutive results for the current expectation.
* Another way to specify consecutive results is to simply write multiple consecutive assignments to the field.
*
* In the Tutorial
*
* @see #returns(Object)
* @see #returns(Object, Object...)
*/
protected static Object result;
/**
* Initializes this set of expectations, entering the record phase.
*
* For each associated {@linkplain Mocked mocked type}, the following tasks are performed:
*
* -
* Redefines the target class for mocking derived from the mocked type.
*
* -
* If the declared type to be mocked is an abstract class, then generates a concrete subclass with empty
* implementations for all inherited abstract methods.
*
* -
* If the mocked type is the declared type of a non-
final
instance field, then creates and assigns a new
* (mocked) instance to that field.
*
*
* After this, test code can start recording invocations on the mocked types and/or mocked instances.
* Each and every such call made from inside the expectation block is recorded.
*
* @see #Expectations(Object...)
* @see #Expectations(int, Object...)
*/
protected Expectations()
{
execution = new RecordAndReplayExecution(this, (Object[]) null);
}
/**
* Same as {@link #Expectations()}, except that one or more classes will be partially mocked according to the
* expectations recorded in the expectation block.
* Such classes are those directly specified as well as those to which any given instances belong.
*
* During the replay phase, any invocations to one of these classes or instances will execute real production code,
* unless a matching invocation was recorded as an expectation inside the block.
*
* For a given {@code Class} object, all constructors and methods will be considered for mocking, from the specified
* class up to but not including {@code java.lang.Object}.
*
* For a given object, all methods will be considered for mocking, from the concrete class of the given
* object up to but not including {@code java.lang.Object}.
* The constructors of those classes will not be considered.
* During replay, invocations to instance methods will only match expectations recorded on the given instance
* (or instances, if more than one was given).
*
* In the
* Tutorial
*
* @param classesOrObjectsToBePartiallyMocked one or more classes or objects whose classes are to be considered for
* partial mocking
*
* @throws IllegalArgumentException if given a class literal for an interface, an annotation, an array, a
* primitive/wrapper type, or a {@linkplain java.lang.reflect.Proxy#isProxyClass(Class) proxy class} created for an
* interface, or if given a value/instance of such a type
*
* @see #Expectations()
* @see #Expectations(int, Object...)
*/
protected Expectations(Object... classesOrObjectsToBePartiallyMocked)
{
execution = new RecordAndReplayExecution(this, classesOrObjectsToBePartiallyMocked);
}
/**
* Identical to {@link #Expectations(Object...)}, but considering that the invocations inside the block will occur in
* a given number of iterations.
*
* The effect of specifying a number of iterations larger than 1 (one) is equivalent to duplicating (like in "copy &
* paste") the whole sequence of strict invocations in the block.
* For any non-strict invocation inside the same block, the effect will be equivalent to multiplying the
* minimum and maximum invocation count by the specified number of iterations.
*
* It's also valid to have multiple expectation blocks for the same test, each with an arbitrary number of
* iterations, and containing any mix of strict and non-strict expectations.
*
* In
* the Tutorial
*
* @param numberOfIterations the positive number of iterations for the whole set of invocations recorded inside the
* block; when not specified, 1 (one) iteration is assumed
*
* @see #Expectations()
* @see #Expectations(Object...)
*/
protected Expectations(int numberOfIterations, Object... classesOrObjectsToBePartiallyMocked)
{
this(classesOrObjectsToBePartiallyMocked);
getCurrentPhase().setNumberOfIterations(numberOfIterations);
}
@Override
final RecordPhase getCurrentPhase()
{
return execution.getRecordPhase();
}
// Methods for setting expected return values //////////////////////////////////////////////////////////////////////
/**
* Specifies that the previously recorded method invocation will return a given value during replay.
*
* More than one return value can be specified for the same invocation by simply calling this method multiple times,
* with the desired consecutive values to be later returned.
* For an strict expectation, the maximum number of expected invocations is automatically adjusted so that one
* invocation for each return value is allowed; if a larger number of invocations is explicitly allowed then the last
* recorded return value is used for all remaining invocations during the replay phase.
*
* It's also possible to specify a sequence of values to be returned by consecutive invocations, by simply passing
* an array, a {@linkplain Collection collection}, an {@linkplain Iterable iterable}, or an
* {@linkplain Iterator iterator}.
* The return type of the recorded method, however, must not be of one of these type non-singular types.
* If it is, the multi-valued argument will be returned by a single invocation at replay time.
*
* If this method is used for a constructor or {@code void} method, the given return value will be ignored,
* but a matching invocation will be allowed during replay; it will simply do nothing.
*
* For a non-void method, if no return value is recorded then all invocations to it will return the appropriate
* default value according to the method return type:
*
* - Primitive: the standard default value is returned (ie {@code false} for {@code boolean}, '\0' for
* {@code char}, {@code 0} for {@code int}, and so on).
* - {@code java.util.Collection} or {@code java.util.List}: returns {@link Collections#EMPTY_LIST}
* - {@code java.util.Set}: returns {@link Collections#EMPTY_SET}.
* - {@code java.util.SortedSet}: returns an unmodifiable empty sorted set.
* - {@code java.util.Map}: returns {@link Collections#EMPTY_MAP}.
* - {@code java.util.SortedMap}: returns an unmodifiable empty sorted map.
* - A reference type (including {@code String} and wrapper types for primitives, and excluding the exact
* collection types above): returns {@code null}.
* - An array type: an array with zero elements (empty) in each dimension is returned.
*
* Finally, value(s) to be returned can also be determined at replay time through a {@link Delegate} instance passed
* as argument to this method (typically created as an anonymous class).
*
* @param value the value to be returned when the method is replayed; must be compatible with the method's return
* type
*
* @throws IllegalStateException if not currently recording an invocation
*
* @see #result
* @see #returns(Object, Object...)
*/
protected final void returns(Object value)
{
getCurrentPhase().addReturnValueOrValues(value);
}
/**
* Equivalent to calling {@link #returns(Object)} two or more times in sequence, except when the associated method
* can return a collection or iterable, an iterator, or an array.
* Specifically, the following situations receive special treatment, according to the declared return type of said
* method:
*
* - If the return type is iterable and can receive a {@link List} value, then the given sequence of values will be
* converted into an {@code ArrayList}; this list will then be returned by matching invocations at replay time.
* - If the return type is {@code SortedSet} or a sub-type, then the given sequence of values will be converted
* into a {@code TreeSet}; otherwise, if it is {@code Set} or a sub-type, then a {@code LinkedHashSet} will be
* created to hold the values; the set will then be returned by matching invocations at replay time.
* - If the return type is {@code Iterator} or a sub-type, then the given sequence of values will be converted into
* a {@code List} and the iterator created from this list will be returned by matching invocations at replay
* time.
* - If the return type is an array, then the given sequence of values will be converted to an array of the same
* type, which will be returned by matching invocations at replay time.
*
* The current expectation will have its upper invocation count automatically set to the total number of values
* specified to be returned. This upper limit can be overridden through the {@code maxTimes} field, if necessary.
*
* If this method is used for a constructor or {@code void} method, the given return values will be ignored,
* but matching invocations will be allowed during replay; they will simply do nothing.
*
* @param firstValue the first value to be returned in the replay phase
* @param remainingValues the remaining values to be returned, in the same order
*
* @throws IllegalStateException if not currently recording an invocation
*/
protected final void returns(Object firstValue, Object... remainingValues)
{
getCurrentPhase().addSequenceOfReturnValues(firstValue, remainingValues);
}
// Methods for defining expectation strictness /////////////////////////////////////////////////////////////////////
/**
* Marks the preceding invocation as belonging to a non-strict expectation.
* Note that all invocations on {@link NonStrict} mocked types/instances will be automatically considered non-strict.
* The same is true for all invocations inside a {@link NonStrictExpectations} block.
*
* For a non-strict expectation, any number (including zero) of invocations with matching arguments can occur while
* in the replay phase, in any order, and they will all produce the same result (usually, the
* {@linkplain #result specified return value}).
* Two or more non-strict expectations can be recorded for the same method or constructor, as long as the arguments
* differ. Argument matchers can be used as well.
*
* Expected invocation counts can also be specified for a non-strict expectation (with one of the "times" fields).
*/
protected final void notStrict()
{
getCurrentPhase().setNotStrict();
}
}