
mockit.Mockit Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2012 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit;
import java.lang.reflect.*;
import java.util.*;
import mockit.internal.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
/**
* Provides static methods for the mocking and stubbing of arbitrary classes, according to specified mock
* classes defined in test code.
* Such methods are intended to be called from test code only.
*
* Once mocked, a "real" method defined in a production class will behave (during test execution) as if its
* implementation was replaced by a call to the corresponding mock method in the mock class.
* Whatever value this mock method returns will be the value returned by the call to the mocked method.
* The mock method can also throw an exception or error, which will then be propagated to the caller of the mocked
* "real" method.
* Therefore, while mocked the original code in the real method is never executed (actually, there's still a way to
* execute the real implementation, although not normally used for testing purposes).
* The same basic rules apply to constructors, which can be mocked by mock methods with the special name "$init".
*
* The methods in this class can be divided in the following groups:
*
* -
* Stubbing API: {@link #stubOut(Class...)}, {@link #stubOutClass(Class, String...)}, and
* {@link #stubOutClass(Class, boolean, String...)}.
*
* -
* Mockups API for state-oriented mocking: {@link MockUp}, {@link #setUpMocks(Object...)},
* {@link #setUpMock(Class, Class)} and its several overloads, {@link #setUpStartupMocks(Object...)},
* {@link #setUpMocksAndStubs(Class...)}, and {@link #tearDownMocks(Class...)} / {@link #tearDownMocks()}.
*
* -
* Proxy-based utilities:
* {@link #newEmptyProxy(ClassLoader, Class)} and its overloads.
* These are merely convenience methods that create empty implementation classes for one or more interfaces, where all
* implemented methods do nothing beyond returning a default value according to the return type of each interface
* method.
* The created classes can be mocked through the Mockups API, and its instances passed to code under test.
*
*
* In the Tutorial:
* Writing state-based tests,
* Reflection-based utilities
*/
public final class Mockit
{
static { Startup.verifyInitialization(true); }
private Mockit() {}
/**
* Stubs out all methods, constructors, and static initializers in the given classes, so that they do nothing
* whenever executed.
*
* Note that any stubbed out constructor will still call a constructor in the super-class, which in turn will be
* executed normally unless also stubbed out.
* The super-constructor to be called is chosen arbitrarily.
* The classes are stubbed out in the order they are given, so make sure any super-class comes first.
*
* Methods with non-void
return type will return the default value for this type, that is, zero for a
* number or {@code char}, {@literal false} for a boolean, empty for an array, or {@literal null} for a reference
* type.
*
* If a different behavior is desired for any method or constructor, then {@link #setUpMocks(Object...)} and the
* other similar methods can be used right after the call to this method.
* They will override any stub previously created with the corresponding mock implementation, if any.
*
* @param realClasses one or more regular classes to be stubbed out
*
* @see
*
* Example
*
* In the Tutorial:
* Using the
* stubbing methods
*/
public static void stubOut(Class>... realClasses)
{
for (Class> realClass : realClasses) {
new RedefinitionEngine(realClass).stubOut();
}
}
/**
* Same as {@link #stubOut(Class...)} for the given class, except that only the specified class members (if any) are
* stubbed out, leaving the rest unaffected.
* Such class members include the methods and constructors defined by the class, plus any static or instance
* initialization blocks it might have.
* Note that if no filters are specified the whole class will be stubbed out.
*
* For methods, the filters are {@linkplain java.util.regex.Pattern regular expressions} for method names, optionally
* followed by parameter type names between parentheses. For constructors, only the parameters are specified.
* For more details about the syntax for mock filters, see the {@link MockClass#stubs} annotation attribute.
*
* The special filter "<clinit>" will match all static initializers in the given class.
*
* To stub out instance field initializers it is necessary to actually specify all constructors in the class, because
* such initialization assignments are copied to each and every constructor by the Java compiler.
*
* @param realClass a regular class to be stubbed out
* @param filters one or more filters that specify which class members (methods, constructors, and/or static
* initialization blocks) to be stubbed out
*
* @see
*
* Example
*
* In the Tutorial:
* Using the
* stubbing methods
*/
public static void stubOutClass(Class> realClass, String... filters)
{
new RedefinitionEngine(realClass, true, filters).stubOut();
}
/**
* The same as {@link #stubOutClass(Class, String...)}, but specifying whether filters are to be inverted or not.
*
* @param inverse indicates whether the mock filters are to be inverted or not; if inverted, only the methods and
* constructors matching them are not mocked
*/
public static void stubOutClass(Class> realClass, boolean inverse, String... filters)
{
new RedefinitionEngine(realClass, !inverse, filters).stubOut();
}
/**
* Same as {@link #stubOutClass(Class, String...)}, but accepting the (fully qualified) name of the real class.
* This is useful when said class is not accessible from the test.
*/
public static void stubOutClass(String realClassName, String... filters)
{
Class> realClass = Utilities.loadClass(realClassName);
new RedefinitionEngine(realClass, true, filters).stubOut();
}
/**
* Same as {@link #stubOutClass(Class, boolean, String...)}, but accepting the (fully qualified) name of the real
* class. This is useful when said class is not accessible from the test.
*/
public static void stubOutClass(String realClassName, boolean inverse, String... filters)
{
Class> realClass = Utilities.loadClass(realClassName);
new RedefinitionEngine(realClass, !inverse, filters).stubOut();
}
/**
* Given a mix of {@linkplain MockClass mock} and real classes, {@linkplain #setUpMock(Class, Class) sets up} each
* mock class for the associated real class, and {@linkplain #stubOut stubs out} each specified regular class.
*
* @param mockAndRealClasses one or more mock classes and/or regular classes to be stubbed out
*/
public static void setUpMocksAndStubs(Class>... mockAndRealClasses)
{
for (Class> mockOrRealClass : mockAndRealClasses) {
RedefinitionEngine redefinition = new RedefinitionEngine(mockOrRealClass);
if (redefinition.isWithMockClass()) {
redefinition.redefineMethods();
}
else {
redefinition.stubOut();
}
}
}
/**
* Sets up the mocks defined in one or more {@linkplain MockClass mock classes}.
*
* After this call, all such mocks are "in effect" until the end of the test method inside which it appears, if this
* is the case.
* If the method is a "before"/"setUp" method which executes before all test methods, then the mocks will remain in
* effect until the end of the test (including any "after"/"tearDown" methods).
*
* Any invocation count constraints specified on mock methods (such as {@code @Mock(invocations = 1)}, for example)
* will be automatically verified after the code under test is executed.
*
* For each call made during test execution to a mocked method, the corresponding mock method is
* called instead.
* A mock method must have the same signature (ie, name and parameters) as the corresponding mocked/real method.
* The return type of the mock method must be the same exact type or a compatible one.
* The {@code throws} clause may differ in any way.
* Note also that the mock method can be static or not, independently of the real method being static or not.
*
* A constructor in the real class can be mocked by a corresponding mock method of name {@code $init}, declared
* with the same parameters and with {@code void} return type.
* It will be called for each new instance of the real class that is created through a call to that constructor, with
* whatever arguments are passed to it.
*
* Class initializers of the real class (one or more {@code static} initialization blocks plus all
* assignments to {@code static} fields) can be mocked by providing a mock method named {@code $clinit} in the mock
* class. This method should return {@code void} and have no declared parameters.
* It will be called at most once, at the time the real class is initialized by the JVM (and since all static
* initializers for that class are mocked, the initialization will have no effect).
*
* Mock methods can gain access to the instance of the real class on which the corresponding real method or
* constructor was called. This requires the mock class to define an instance field of name "it",
* the same type as the real class, and accessible from that class (in general, this means the field will have to be
* {@code public}). Such a field will always be set to the appropriate real class instance, whenever a mock method is
* called. Note that through this field the mock class will be able to call any accessible instance method on the
* real class, including the real method corresponding to the current mock method. In this case, however, such calls
* are not allowed by default because they lead to infinite recursion, with the mock calling itself indirectly
* through the redefined real method. If the real method needs to be called from the mock method, then the latter
* must be declared as {@linkplain mockit.Mock#reentrant reentrant}.
*
* @param mockClassesOrInstances one or more classes ({@code Class} objects) or instances of classes which define
* arbitrary methods and/or constructors, where the ones annotated as {@linkplain Mock mocks} will be used to
* redefine corresponding real methods/constructors in a designated {@linkplain MockClass#realClass() real class}
* (usually, a class on which the code under test depends on)
*
* @throws IllegalArgumentException if a given mock class fails to specify the corresponding real class using the
* {@code @MockClass(realClass = ...)} annotation; or if a mock class defines a mock method for which no
* corresponding real method or constructor exists in the real class;
* or if the real method matching a mock method is {@code abstract}
*
* @see #tearDownMocks(Class[])
* @see
*
* Example
*
* In the Tutorial:
* Using the
* @MockClass
annotation
*/
public static void setUpMocks(Object... mockClassesOrInstances)
{
for (Object mockClassOrInstance : mockClassesOrInstances) {
Class> mockClass;
Object mock;
if (mockClassOrInstance instanceof Class>) {
mockClass = (Class>) mockClassOrInstance;
mock = null;
}
else {
mockClass = mockClassOrInstance.getClass();
mock = mockClassOrInstance;
}
new RedefinitionEngine(mock, mockClass).redefineMethods();
}
}
/**
* Sets up the startup {@linkplain Mock mocks} defined in one or more mock classes, just like
* {@link #setUpMocks(Object...)} does for regular mock classes.
* The difference is in the lifetime of the mocks, which will last to the end of the test run.
* Consequently, this method should only be called once, before the first test begins execution.
* One way to achieve this is to put the call in the static initializer of a common base class extended by all test
* classes in the suite. Another way is by configuring what happens at startup through external means.
*
* There are three ways to set up mock classes at startup time:
*
* - Define a value for the "
jmockit-mocks
" system property, as a comma-separated list of fully
* qualified class names.
* - Add a custom "
jmockit.properties
" file to the classpath, with an entry for the
* "jmockit-mocks
" (or just "mocks
") property.
*
* - Specify the "
-javaagent:jmockit.jar=<agentArgs>
" JVM argument, with "agentArgs
"
* containing one or more mock class names, separated by semicolons if more than one.
*
*
* Note that option two above makes it possible to package a whole set of reusable mock classes in a jar file,
* provided it contains a suitable jmockit.properties
file.
* By simply adding the jar to the classpath before jmockit.jar
, the specified mock classes
* will be loaded and applied automatically on every test run, as soon as JMockit itself gets initialized.
*
* @param mockClassesOrInstances one or more mock classes (either Class
literals or fully qualified
* class names) or instances of mock classes
*
* @throws IllegalArgumentException if a given mock class fails to specify the corresponding real class using the
* {@code @MockClass(realClass = ...)} annotation; or if a mock class defines a mock method for which no
* corresponding real method or constructor exists in the real class;
* or if the real method matching a mock method is {@code abstract}
*
* @see
*
* Example
*
* In the Tutorial:
* Using mocks and stubs over
* entire test classes and suites
*/
public static void setUpStartupMocks(Object... mockClassesOrInstances)
{
for (Object mockClassOrInstance : mockClassesOrInstances) {
Class> mockClass;
Object mock;
if (mockClassOrInstance instanceof Class>) {
mockClass = (Class>) mockClassOrInstance;
mock = null;
}
else if (mockClassOrInstance instanceof String) {
String className = ((String) mockClassOrInstance).trim();
if (className.length() == 0) continue;
mockClass = Utilities.loadClass(className);
mock = null;
}
else {
mockClass = mockClassOrInstance.getClass();
mock = mockClassOrInstance;
}
new RedefinitionEngine(mock, mockClass).setUpStartupMock();
}
}
/**
* Similar to {@link #setUpMocks(Object...)}, but accepting a single mock and its corresponding real class.
*
* Useful when the real class is not known in advance, such as when it is determined at runtime through configuration
* of by creating a {@link Proxy} for an interface.
*
* @param realClass the class to be mocked that is used by code under test
* @param mock an instance of the class containing the mock methods for the real class
*
* @see
*
* Example
*/
public static void setUpMock(Class> realClass, Object mock)
{
Class> mockClass = mock.getClass();
new RedefinitionEngine(realClass, mock, mockClass).redefineMethods();
}
/**
* Same as {@link #setUpMock(Class, Object)}, but accepting the (fully qualified) name of the real class.
* This is useful when said class is not accessible from the test.
*/
public static void setUpMock(String realClassName, Object mock)
{
Class> realClass = Utilities.loadClass(realClassName);
setUpMock(realClass, mock);
}
/**
* Similar to {@link #setUpMocks(Object...)}, but accepting a single mock class and its corresponding real class.
*
* Can also be useful when the real class is not known in advance, such as when it is determined at runtime through
* configuration or by creating a {@link Proxy} for an interface.
*
* @param realClass the class to be mocked that is used by code under test
* @param mockClass the class containing the mock methods for the real class
*
* @see
*
* Example
*/
public static void setUpMock(Class> realClass, Class> mockClass)
{
new RedefinitionEngine(realClass, null, mockClass).redefineMethods();
}
/**
* Same as {@link #setUpMock(Class, Class)}, but accepting the (fully qualified) name of the real class.
* This is useful when said class is not accessible from the test.
*
* @see
*
* Example
*/
public static void setUpMock(String realClassName, Class> mockClass)
{
Class> realClass = Utilities.loadClass(realClassName);
setUpMock(realClass, mockClass);
}
/**
* Sets up the mocks defined in the given mock class.
*
* If the type {@linkplain MockClass#realClass referred to} by the mock class is actually an interface, then a
* {@linkplain #newEmptyProxy(ClassLoader, Class) new empty proxy} is created.
*
* @param mockClassOrInstance the mock class itself (given by its {@code Class} literal), or an instance of the mock
* class
*
* @return the new proxy instance created for the mocked interface, or {@code null} otherwise
*
* @throws IllegalArgumentException if a given mock class fails to specify the corresponding real class using the
* {@code @MockClass(realClass = ...)} annotation; or if a mock class defines a mock method for which no
* corresponding real method or constructor exists in the real class;
* or if the real method matching a mock method is {@code abstract}
*
* @see #setUpMock(Class, Object)
* @see #setUpMocks(Object...)
* @see
*
* Example
*/
public static T setUpMock(Object mockClassOrInstance)
{
Class> mockClass;
Object mock;
if (mockClassOrInstance instanceof Class>) {
mockClass = (Class>) mockClassOrInstance;
mock = null;
}
else {
mockClass = mockClassOrInstance.getClass();
mock = mockClassOrInstance;
}
RedefinitionEngine redefinition = new RedefinitionEngine(mock, mockClass);
Class> realClass = redefinition.getRealClass();
T proxy = null;
if (realClass.isInterface()) {
//noinspection unchecked
proxy = (T) newEmptyProxy(mockClass.getClassLoader(), realClass);
redefinition.setRealClass(proxy.getClass());
}
redefinition.redefineMethods();
return proxy;
}
/**
* Discards any mocks currently in effect, for all test scopes: the current test method (if any), the current test
* (which starts with the first "before" method and continues until the last "after" method), the current test class
* (which includes all code from the first "before class" method to the last "after class" method), and the current
* test suite.
*
* Notice that a call to this method will tear down all mock classes that were applied through use of the
* Mockups API that are still in effect, as well as any mock classes or stubs applied to the current test class
* through {@code @UsingMocksAndStubs}.
* In other words, it would effectively prevent mocks to be set up at the test class and test suite levels.
* So, use it only if necessary and if it won't discard mock classes that should remain in effect.
* Consider using {@link #tearDownMocks(Class...)} instead, which lets you restrict the set of real classes to be
* restored.
*
* JMockit will automatically restore classes mocked by a test at the end of its execution, as well as all classes
* mocked for the test class as a whole (through a "before class" method or an {@code @UsingMocksAndStubs}
* annotation) before the first test in the next test class is executed.
*
* @see
*
* Example
*/
public static void tearDownMocks()
{
TestRun.mockFixture().restoreAndRemoveRedefinedClasses(null);
TestRun.getMockClasses().getRegularMocks().discardInstances();
}
/**
* Discards any mocks set up for the specified classes that are currently in effect, for all test scopes: the current
* test method (if any), the current test (which starts with the first "before" method and continues until the last
* "after" method), the current test class (which includes all code from the first "before class" method to the last
* "after class" method), and the current test suite.
*
* Notice that if one of the given real classes has a mock class applied at the level of the test class, calling this
* method would negate the application of that mock class.
* JMockit will automatically restore classes mocked by a test at the end of its execution, as well as all classes
* mocked for the test class as a whole (through a "before class" method or an {@code @UsingMocksAndStubs}
* annotation) before the first test in the next test class is executed.
*
* @param realClasses one or more real classes from production code, which may have mocked methods
*/
public static void tearDownMocks(Class>... realClasses)
{
Set> classesToRestore = new HashSet>();
Collections.addAll(classesToRestore, realClasses);
TestRun.mockFixture().restoreAndRemoveRedefinedClasses(classesToRestore);
}
/**
* Same as {@link #newEmptyProxy(ClassLoader, Class)}, but with the class loader obtained from the interface to be
* proxied. Note that this may lead to a {@code NoClassDefFoundError} if that interface was loaded by the boot class
* loader (usually, when it's a JRE class).
* Therefore, you should only use this method for application-defined interfaces.
*
* This method is just a convenience for some uses of the Mockups API.
* In JMockit Expectations in particular, mocked instances will be automatically created and assigned to any
* mock fields or parameters.
*
* @see
*
* Example
*/
public static E newEmptyProxy(Class interfaceToBeProxied)
{
return newEmptyProxy(interfaceToBeProxied.getClassLoader(), interfaceToBeProxied);
}
/**
* Creates a {@link Proxy} implementation for a given interface, in which all methods are empty.
* Non-void methods will return a default value according to the return type: {@literal 0} for {@code int},
* {@literal null} for a reference type, and so on.
*
* The {@code equals}, {@code hashCode}, and {@code toString} methods inherited from {@code java.lang.Object} are
* overridden with an appropriate implementation in each case:
* {@code equals} is implemented by comparing the two object references (the proxy instance and the method argument)
* for equality; {@code hashCode} is implemented to return the identity hash code for the proxy instance; and
* {@code toString} returns the standard string representation that {@code Object#toString} would have returned.
*
* This method is just a convenience for some uses of the Mockups API.
* In JMockit Expectations in particular, mocked instances will be automatically created and assigned to any
* mock fields or parameters.
*
* @param loader the class loader under which to define the proxy class; usually this would be the application class
* loader, which can be obtained from any application class
* @param interfaceToBeProxied a {@code Class} object for an interface
*
* @return the created proxy instance
*
* @see #newEmptyProxy(Class)
* @see #newEmptyProxy(Type...)
* @see
*
* Example
*/
public static E newEmptyProxy(ClassLoader loader, Class interfaceToBeProxied)
{
Class>[] interfaces = loader == null ?
new Class>[] {interfaceToBeProxied} : new Class>[] {interfaceToBeProxied, EmptyProxy.class};
//noinspection unchecked
return (E) Proxy.newProxyInstance(loader, interfaces, MockInvocationHandler.INSTANCE);
}
/**
* Creates a {@link Proxy} implementation for a given set of interface types.
* In this created class all methods will be empty, with return values for non-void methods being the appropriate
* default value ({@literal 0} for {@code int}, {@literal null} for a reference type, and so on).
*
* The {@code equals}, {@code hashCode}, and {@code toString} methods inherited from {@code java.lang.Object} are
* overridden with an appropriate implementation in each case:
* {@code equals} is implemented by comparing the two object references (the proxy instance and the method argument)
* for equality; {@code hashCode} is implemented to return the identity hash code for the proxy instance; and
* {@code toString} returns the standard string representation that {@code Object#toString} would have returned.
*
* This method is just a convenience for some uses of the Mockups API.
* In JMockit Expectations in particular, mocked instances will be automatically created and assigned to any
* mock fields or parameters.
*
* @param interfacesToBeProxied one or more {@code Type} objects, each of which can be a {@code Class} object for an
* interface, a {@link ParameterizedType} whose raw type is an interface, or a {@link TypeVariable} whose bounds are
* interfaces
*
* @return the created proxy instance
*/
public static E newEmptyProxy(Type... interfacesToBeProxied)
{
return Utilities.newEmptyProxy(null, interfacesToBeProxied);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy