![JAR search and dependency download from the Maven repository](/logo.png)
mockit.MockUp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmockit Show documentation
Show all versions of jmockit Show documentation
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.
/*
* Copyright (c) 2006-2013 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.mockups.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
/**
* A base class used in the creation of a mock-up for a class or interface.
* Such mock-ups can be used in state-based unit tests or as fake implementations for use in
* integration tests.
*
*
* // Define and apply a mock-up before exercising the code under test:
* new MockUp<SomeClass>() {
* @Mock int someMethod(int i) { assertTrue(i > 0); return 123; }
* @Mock(maxInvocations = 2) void anotherMethod(int i, String s) { /* validate arguments */ }
* };
*
* One or more mock methods annotated {@linkplain Mock as such} must be defined in the concrete subclass.
* Each {@code @Mock} method should have a matching method or constructor in the mocked class/interface.
* At runtime, the execution of a mocked method/constructor will get redirected to the corresponding mock method.
*
* In the Tutorial
*
* @param specifies the type (class, interface, etc.) to be mocked; multiple interfaces can be mocked by defining
* a type variable in the test class or test method, and using it as the type argument;
* if the type argument itself is a parameterized type, then only its raw type is considered for mocking
*
* @see #MockUp()
* @see #MockUp(Class)
* @see #getMockInstance()
* @see #tearDown()
*/
public abstract class MockUp
{
static { Startup.verifyInitialization(); }
private Set> classesToRestore;
private final T mockInstance;
/**
* Applies the {@linkplain Mock mock methods} defined in the concrete subclass to the class or interface specified
* through the type parameter.
*
* When one or more interfaces are specified to be mocked, a mocked proxy class that implements the interfaces is
* created, with the proxy instance made available through a call to {@link #getMockInstance()}.
*
* @throws IllegalArgumentException if no type to be mocked was specified;
* or if there is a mock method for which no corresponding real method or constructor is found;
* or if the real method matching a mock method is {@code abstract}
*
* @see #MockUp(Class)
*/
protected MockUp()
{
validateMockingAllowed();
tearDownPreviousMockUpIfSameMockClassAlreadyApplied();
Type typeToMock = MockClassSetup.getTypeToMock(getClass());
if (typeToMock instanceof Class>) {
//noinspection unchecked
mockInstance = redefineClassOrImplementInterface((Class) typeToMock, null);
}
else if (typeToMock instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) typeToMock;
//noinspection unchecked
Class realClass = (Class) parameterizedType.getRawType();
mockInstance = redefineClassOrImplementInterface(realClass, parameterizedType);
}
else { // a TypeVariable
mockInstance = createMockInstanceForMultipleInterfaces(typeToMock);
}
}
private void validateMockingAllowed()
{
if (TestRun.isInsideNoMockingZone()) {
throw new IllegalStateException("Invalid place to apply a mock-up");
}
}
private void tearDownPreviousMockUpIfSameMockClassAlreadyApplied()
{
Class> mockClass = getClass();
MockUp> previousMock = TestRun.getMockClasses().findMock(mockClass);
if (previousMock != null) {
previousMock.tearDown();
}
}
private T redefineClassOrImplementInterface(Class classToMock, ParameterizedType typeToMock)
{
if (classToMock.isInterface()) {
return new MockedImplementationClass(this).generate(classToMock, typeToMock);
}
classesToRestore = redefineMethods(classToMock, typeToMock);
return null;
}
private Set> redefineMethods(Class realClass, ParameterizedType mockedType)
{
return Startup.initializing ? null : new MockClassSetup(realClass, mockedType, this, null).redefineMethods();
}
private T createMockInstanceForMultipleInterfaces(Type typeToMock)
{
T proxy = EmptyProxy.Impl.newEmptyProxy(null, typeToMock);
//noinspection unchecked
redefineMethods((Class) proxy.getClass(), null);
return proxy;
}
/**
* Applies the {@linkplain Mock mock methods} defined in the concrete subclass to the given class/interface.
*
* In most cases, the constructor with no parameters can be used. This variation should be used only when the type
* to be mocked is not accessible or known to the test.
*
* @see #MockUp()
*/
@SuppressWarnings("unchecked")
protected MockUp(Class> classToMock)
{
validateMockingAllowed();
tearDownPreviousMockUpIfSameMockClassAlreadyApplied();
if (classToMock.isInterface()) {
mockInstance = new MockedImplementationClass(this).generate((Class) classToMock, null);
}
else {
classesToRestore = redefineMethods((Class) classToMock, null);
mockInstance = null;
}
}
/**
* Returns the mock instance created for the mocked interface(s), or {@literal null} if a class was specified to be
* mocked instead.
* This mock instance belongs to a dynamically generated class which implements the mocked interface(s).
*
* For a given mock-up instance, this method always returns the same mock instance.
*
* All methods in the generated implementation class are empty, with non-void methods returning 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 mock instance and the method argument)
* for equality; {@code hashCode} is implemented to return the identity hash code for the mock instance; and
* {@code toString} returns the standard string representation that {@code Object#toString} would have returned.
*/
public final T getMockInstance() { return mockInstance; }
/**
* Discards the mock methods originally set up by instantiating this mock-up object, restoring mocked methods to
* their original behaviors.
*
* JMockit will automatically restore classes mocked by a test at the end of its execution, as well as classes
* mocked for the whole test class before the first test in the next test class is executed.
* Therefore, this method should rarely be used, if ever.
*/
public final void tearDown()
{
if (classesToRestore != null) {
TestRun.mockFixture().restoreAndRemoveRedefinedClasses(classesToRestore);
TestRun.getMockClasses().removeMock(this);
classesToRestore = null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy