
mockit.Expectations Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2013 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.*;
/**
* A set of expected and/or allowed method/constructor invocations on the mocked types/instances that
* have been made available to the test through mock fields and/or mock parameters.
*
*
* new Expectations() {{
* mock1.expectedMethod(anyInt); result = 123; times = 2;
* mock2.allowedMethod(1, "test"); result = new String[] {"Abc", "xyz"};
* }};
*
* // Now exercise the tested code according to the recorded expectations.
*
* Typically, this class is used by extending it with anonymous inner classes inside test methods, the so
* called expectation blocks.
* Inside such blocks, expectations are recorded on mocked types or mocked instances 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.
*
* There are several special fields and methods which can be used in the expectation block, to: a) record desired return
* values or exceptions/errors to be thrown ({@link #result}, {@link #returns(Object, Object...)}); b) relax or
* constrain the matching of argument values ({@link #anyInt}, {@link #anyString}, {@link #withNotNull()}, etc.);
* c) relax or constrain the expected and/or allowed number of matching invocations ({@link #times}, {@link #minTimes},
* {@link #maxTimes}).
*
* 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.
*
* -
* All expectations recorded inside an {@code Expectations} immediate subclass will be strict, meaning that
* matching invocations are expected to occur in the same order during the replay phase, and that non-recorded
* invocations are not allowed.
*
* -
* 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, unless the
* mock field/parameter was declared to be {@linkplain Injectable @Injectable}.
* If such verification on non-injectable instances 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(Integer, Object...) iterated invocations}.
*
*
*
* In the
* Tutorial
*
* @see #Expectations()
* @see #Expectations(Object...)
* @see #Expectations(Integer, Object...)
* @see NonStrictExpectations
*/
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 a {@link Throwable} then it will be thrown when a matching invocation later occurs.
* Otherwise, it's assumed to be a return value for a non-void
method, and will be returned
* from a matching invocation.
*
* If the recorded 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, as it only applies to
* return values.
*
* Assigning a value whose type differs from the method return type will cause an {@code IllegalArgumentException} to
* be thrown, unless it can be safely converted to the return type.
* One such conversion is from an array to a collection or iterator.
* Another is from an array of at least two dimensions to a map, with the first dimension providing the keys and the
* second the values.
* Yet another conversion is from a single value to a container type holding that value.
*
* Additionally, if the value assigned to the field is an array or is of a type assignable to {@link Iterable} or
* {@link Iterator}, and the return type is single-valued, then the assigned multi-valued result is taken as a
* sequence of consecutive results for the expectation.
* Another way to specify consecutive results is to simply write multiple consecutive assignments to the field, for
* the same expectation.
*
* Custom results can be provided through a {@linkplain mockit.Delegate} object assigned to the field.
* This applies to {@code void} and non-void
methods, as well as for constructors.
*
* Finally, when recording an expectation on a constructor of a mocked class, an arbitrary instance of said
* class can be assigned to the field.
* In this case, the assigned instance will be used as a "replacement" for all invocations to
* instance methods made on other instances, provided they get created sometime later through a
* matching constructor invocation.
*
* 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(Integer, 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(Integer, 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(Integer 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 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);
}
/**
* Specifies that the previously recorded method invocation will return a given sequence of values during replay.
*
* Using this method is equivalent to calling {@link #returns(Object)} two or more times in sequence, except when the
* recorded method can return an iterable (including any {@code Collection} subtype), an iterator, or an array:
*
* - 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);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy