mockit.Mockit Maven / Gradle / Ivy
/*
* JMockit Annotations
* Copyright (c) 2006-2010 Rogério Liesenfeld
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
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 from production code,
* 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 corresponding mock
* constructors or by special mock methods.
*
* 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...)}.
*
* -
* Annotations 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 Annotations API, and its instances passed to code
* under test.
*
*
* Tutorial:
* Writing state-based tests,
* Reflection-based utilities
*/
public final class Mockit
{
static
{
Startup.verifyInitialization();
}
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-{@code 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
*/
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
*/
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 they are explicitly {@linkplain #tearDownMocks(Class...) torn down} in an "after"/"tearDown" method.
*
* 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 constructor in the mock
* class, declared with the same signature.
* However, since a constructor can only be called on a freshly created instance, it is generally recommended to
* declare a mock method of name {@code $init} instead (which can also be {@code static}).
* This method should have {@code void} return type and must have the same declared parameters as the mocked
* constructor. 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 any mock class fails to specify the corresponding real class using the
* {@code @MockClass(realClass = ...)} annotation
*
* @see Example
*/
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, false).redefineMethods();
}
}
/**
* Sets up the startup mocks defined in one or more mock classes, similarly to
* {@link #setUpMocks(Object...)}. The difference is in the lifetime of the mocks, which will last to the end of the
* current test suite execution.
* 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 JMockit to apply one or more of the mock classes at startup.
*
* There are two mechanisms that allow specifying mock classes to be loaded at JMockit startup time:
*
* - Using the "-javaagent:jmockit.jar=<agentArgs>" JVM argument, where "agentArgs" contains one or more
* mock class names (separated by semicolons if more than one).
*
* - Using a customized "jmockit.properties" file, which must precede the standard file located inside jmockit.jar
* (see comments in that file for more details).
*
*
* Note that if you pass all desired mock classes to JMockit at startup using one of these two mechanisms, this
* method won't be used. However, it's also possible to pass only one of those mock classes to JMockit and then call
* this method in the no-args constructor of the chosen mock class, to cause the remaining mock classes to be
* applied.
*
* Note also that it's possible to package a whole set of mock classes in a jar file containing a jmockit.properties
* file and then, by simply adding the jar to the classpath before jmockit.jar, to have it loaded and
* applied automatically for any test suite execution, as soon as JMockit itself is initialized.
*
* @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 any mock class fails to specify the corresponding real class using the
* {@code @MockClass(realClass = ...)} annotation
*
* @see Example
*/
public static void setUpStartupMocks(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, false).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/constructors 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/constructors 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 the mock class fails to specify an interface or class using the
* {@code @MockClass(realClass = ...)} annotation
*
* @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, false);
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
* Annotations 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 method at the end of that test method's 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()
{
MockFixture mockFixture = TestRun.mockFixture();
Set> redefinedClasses = mockFixture.getRedefinedClasses();
mockFixture.restoreAndRemoveRedefinedClasses(redefinedClasses);
assert mockFixture.getRedefinedClassCount() == 0;
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 method at the end of that test method's 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.
*
* In practice, this method should only be used inside "after" methods ({@code tearDown()} in a JUnit 3.8 test
* class), since mock classes set up in a "before" or {@code setUp()} method are not automatically
* discarded.
*
* @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 Annotations 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 Annotations 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 Annotations 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)
{
List> interfaces = new ArrayList>();
for (Type type : interfacesToBeProxied) {
addInterface(interfaces, type);
}
interfaces.add(EmptyProxy.class);
ClassLoader loader = Mockit.class.getClassLoader();
Class>[] interfacesArray = interfaces.toArray(new Class>[interfaces.size()]);
//noinspection unchecked
return (E) Proxy.newProxyInstance(loader, interfacesArray, MockInvocationHandler.INSTANCE);
}
private static void addInterface(List> interfaces, Type type)
{
if (type instanceof Class>) {
interfaces.add((Class>) type);
}
else if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
interfaces.add((Class>) paramType.getRawType());
}
else if (type instanceof TypeVariable) {
TypeVariable> typeVar = (TypeVariable>) type;
addBoundInterfaces(interfaces, typeVar.getBounds());
}
}
private static void addBoundInterfaces(List> interfaces, Type[] bounds)
{
for (Type bound : bounds) {
addInterface(interfaces, bound);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy