View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import java.util.Collections;
12  import java.util.Iterator;
13  import java.util.List;
14  import java.util.Optional;
15  
16  import mockit.internal.expectations.RecordAndReplayExecution;
17  import mockit.internal.expectations.RecordPhase;
18  
19  /**
20   * Used to <em>record</em> expectations on {@linkplain Mocked mocked} types and their instances.
21   * <p>
22   * Each recorded expectation is intended to match one or more method or constructor invocations, that we expect will
23   * occur during the execution of code under test, and which need to exhibit some specific behavior for the purposes of
24   * the test. When a match is detected, the recorded {@linkplain #result result} (if any) is returned to the caller.
25   * Alternatively, a recorded exception/error is thrown, or an arbitrary {@linkplain Delegate delegate} method is
26   * executed.
27   * <p>
28   * Expectations are recorded simply by invoking the desired method or constructor on the mocked type/instance, during
29   * the initialization of an <code>Expectations</code> object. This is done by instantiating an anonymous subclass
30   * containing an instance initialization body, or as we call it, an <em>expectation block</em>:
31   *
32   * <pre>{@code
33   * // <em>Record</em> one or more expectations on available mocked types/instances.
34   * new Expectations() {{
35   *    <strong>mock1</strong>.expectedMethod(anyInt); result = 123; times = 2;
36   *    <strong>mock2</strong>.anotherExpectedMethod(1, "test"); result = "Abc";
37   * }};
38   *
39   * // Exercise tested code, with previously recorded expectations now available for <em>replay</em>.
40   * codeUnderTest.doSomething();
41   * }</pre>
42   *
43   * During replay, invocations matching a recorded expectation must occur at least <em>once</em> (unless specified
44   * otherwise); if, by the end of the test, no matching invocation occurred for a given recorded expectation, the test
45   * will fail with a <code>MissingInvocation</code> error.
46   * <p>
47   * When multiple expectations are recorded, matching invocations are allowed to occur in a <em>different</em> order. So,
48   * the order in which expectations are recorded is not significant.
49   * <p>
50   * Besides the special {@link #result} field already mentioned, there are several other fields and methods which can be
51   * used inside the expectation block: a) {@link #returns(Object, Object, Object...)}, a convenience method for returning
52   * a <em>sequence</em> of values; b) argument matchers such as {@link #anyInt}, {@link #anyString},
53   * {@link #withNotNull()}, etc., which relax or constrain the matching of argument values; c) the {@link #times},
54   * {@link #minTimes}, and {@link #maxTimes} fields, which relax or constrain the expected and/or allowed number of
55   * matching invocations.
56   * <p>
57   * By default, the exact instance on which instance method invocations will occur during replay is <em>not</em> verified
58   * to be the same as the instance used when recording the expectation. That said, instance-specific matching can be
59   * obtained by declaring the mocked type as {@linkplain Injectable @Injectable}, or by declaring multiple mock fields
60   * and/or mock parameters of the same mocked type (so that separate expectations can be recorded for each mock
61   * instance).
62   * <p>
63   * Invocations occurring during replay, whether they matched recorded expectations or not, can be explicitly verified
64   * <em>after</em> exercising the code under test. To that end, we use a set of complementary base classes:
65   * {@link Verifications}, {@link VerificationsInOrder}, and {@link FullVerifications}. Similar to expectation blocks,
66   * these classes allow us to create <em>verification</em> blocks.
67   *
68   * @see #Expectations()
69   * @see #Expectations(Object...)
70   * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#expectation" target="tutorial">Tutorial</a>
71   */
72  public class Expectations extends Invocations {
73      /**
74       * A value assigned to this field will be taken as the result for the expectation that is being recorded.
75       * <p>
76       * If the value is a {@link Throwable} then it will be <em>thrown</em> when a matching invocation later occurs.
77       * Otherwise, it's assumed to be a <em>return value</em> for a non-<code>void</code> method, and will be returned
78       * from a matching invocation.
79       * <p>
80       * If no result is recorded for a given expectation, then all matching invocations will return the appropriate
81       * default value according to the method return type:
82       * <ul>
83       * <li>Most <code>java.lang</code> types (<code>String</code>, <code>Object</code>, etc.): returns
84       * <code>null</code>.</li>
85       * <li><code>java.math</code> types (<code>BigDecimal</code>, etc.): returns <code>null</code>.</li>
86       * <li>Primitive/wrapper types: returns the standard default value (<code>false</code> for
87       * <code>boolean/Boolean</code>, <code>0</code> for <code>int/Integer</code>, and so on).</li>
88       * <li><code>java.util.List</code>, <code>java.util.Collection</code>, or <code>java.lang.Iterable</code>: returns
89       * {@link Collections#EMPTY_LIST}.</li>
90       * <li><code>java.util.Iterator</code> or <code>java.util.ListIterator</code>: returns an empty iterator.</li>
91       * <li><code>java.util.Set</code>: returns {@link Collections#EMPTY_SET}.</li>
92       * <li><code>java.util.SortedSet</code>: returns an unmodifiable empty sorted set.</li>
93       * <li><code>java.util.Map</code>: returns {@link Collections#EMPTY_MAP}.</li>
94       * <li><code>java.util.SortedMap</code>: returns an unmodifiable empty sorted map.</li>
95       * <li><code>java.util.Optional</code>: returns {@link Optional#empty()}.</li>
96       * <li>Other reference types: returns a mocked instance through cascading.</li>
97       * <li>Array types: returns an array with zero elements (empty) in each dimension.</li>
98       * </ul>
99       * When an expectation is recorded for a method which actually <em>returns</em> an exception or error (as opposed to
100      * <em>throwing</em> one), then the {@link #returns(Object, Object, Object...)} method should be used instead, as it
101      * only applies to return values.
102      * <p>
103      * Assigning a value whose type differs from the method return type will cause an
104      * <code>IllegalArgumentException</code> to be thrown, unless it can be safely converted to the return type. One
105      * such conversion is from an array to a collection or iterator. Another is from an array of at least two dimensions
106      * to a map, with the first dimension providing the keys and the second the values. Yet another conversion is from a
107      * single value to a container type holding that value.
108      * <p>
109      * A sequence of <em>consecutive results</em> can be recorded simply by assigning the field multiple times for the
110      * same expectation. Alternatively, the desired sequence of results for a single-valued return type can be recorded
111      * by assigning an array, an {@link Iterable}, or an {@link Iterator} containing the individual results in order.
112      * <p>
113      * Results that depend on some programming logic can be provided through a {@linkplain Delegate} object assigned to
114      * the field. This applies to <code>void</code> and non-<code>void</code> methods, as well as to constructors.
115      *
116      * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#results" target="tutorial">Tutorial</a>
117      */
118     @Nullable
119     protected Object result;
120 
121     /**
122      * Registers one or more expectations recorded on available mocked types and/or mocked instances, as written inside
123      * the instance initialization body of an anonymous subclass.
124      *
125      * @see #Expectations(Object...)
126      * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#expectation" target="tutorial">Tutorial</a>
127      */
128     protected Expectations() {
129         RecordAndReplayExecution execution = new RecordAndReplayExecution(this, (Object[]) null);
130         // noinspection ConstantConditions
131         currentPhase = execution.getRecordPhase();
132     }
133 
134     /**
135      * Same as {@link #Expectations()}, except that one or more objects will be partially mocked according to the
136      * expectations recorded in the expectation block.
137      * <p>
138      * During replay, any invocations to instance methods on these objects will execute real production code, unless a
139      * matching expectation was recorded.
140      *
141      * @param objectsToBePartiallyMocked
142      *            one or more objects to be partially mocked
143      *
144      * @throws IllegalArgumentException
145      *             if given a <code>Class</code> object, or if given a value/instance of an interface, an annotation, an
146      *             array, a primitive/wrapper type, a synthetic class, or a
147      *             {@linkplain java.lang.reflect.Proxy#isProxyClass(Class) proxy class}
148      *
149      * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#partial" target="tutorial">Tutorial</a>
150      */
151     protected Expectations(@NonNull Object... objectsToBePartiallyMocked) {
152         RecordAndReplayExecution execution = new RecordAndReplayExecution(this, objectsToBePartiallyMocked);
153         // noinspection ConstantConditions
154         currentPhase = execution.getRecordPhase();
155     }
156 
157     /**
158      * Specifies that the previously recorded method invocation will return a given sequence of values during replay.
159      * <p>
160      * Calling this method is equivalent to assigning the {@link #result} field two or more times in sequence, or
161      * assigning it a single time with an array or iterable containing the same sequence of values.
162      * <p>
163      * Certain data conversions will be applied, depending on the return type of the recorded method:
164      * <ol>
165      * <li>If the return type is iterable and can receive a {@link List} value, then the given sequence of values will
166      * be converted into an <code>ArrayList</code>; this list will then be returned by matching invocations at replay
167      * time.</li>
168      * <li>If the return type is <code>SortedSet</code> or a sub-type, then the given sequence of values will be
169      * converted into a <code>TreeSet</code>; otherwise, if it is <code>Set</code> or a sub-type, then a
170      * <code>LinkedHashSet</code> will be created to hold the values; the set will then be returned by matching
171      * invocations at replay time.</li>
172      * <li>If the return type is <code>Iterator</code> or a sub-type, then the given sequence of values will be
173      * converted into a <code>List</code> and the iterator created from this list will be returned by matching
174      * invocations at replay time.</li>
175      * <li>If the return type is an array, then the given sequence of values will be converted to an array of the same
176      * type, which will be returned by matching invocations at replay time.</li>
177      * </ol>
178      * The current expectation will have its upper invocation count automatically set to the total number of values
179      * specified to be returned. This upper limit can be overridden through the <code>maxTimes</code> field, if
180      * necessary.
181      *
182      * @param firstValue
183      *            the first value to be returned at replay time
184      * @param secondValue
185      *            the second value to be returned at replay time
186      * @param remainingValues
187      *            any remaining values to be returned, in the same order
188      *
189      * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#results" target="tutorial">Tutorial</a>
190      */
191     protected final void returns(@Nullable Object firstValue, @Nullable Object secondValue,
192             @NonNull Object... remainingValues) {
193         int n = remainingValues.length;
194         Object[] values = new Object[2 + n];
195         values[0] = firstValue;
196         values[1] = secondValue;
197         System.arraycopy(remainingValues, 0, values, 2, n);
198 
199         ((RecordPhase) currentPhase).addSequenceOfReturnValues(values);
200     }
201 }