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

mockit.Mockit Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for developer (unit/integration) testing. It contains mocking APIs and other tools, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

There is a newer version: 1.7
Show newest version
/*
 * 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 - 2024 Weber Informatics LLC | Privacy Policy