All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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: *

    *
  1. Define a value for the "jmockit-mocks" system property, as a comma-separated list of fully * qualified class names.
  2. *
  3. Add a custom "jmockit.properties" file to the classpath, with an entry for the * "jmockit-mocks" (or just "mocks") property. *
  4. *
  5. Specify the "-javaagent:jmockit.jar=<agentArgs>" JVM argument, with "agentArgs" * containing one or more mock class names, separated by semicolons if more than one. *
  6. *
* 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