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

mockit.MockUp Maven / Gradle / Ivy

/*
 * 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 org.jetbrains.annotations.*;

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(); } } @Nullable private T redefineClassOrImplementInterface(@NotNull Class classToMock, @Nullable ParameterizedType typeToMock) { if (classToMock.isInterface()) { return new MockedImplementationClass(this).generate(classToMock, typeToMock); } classesToRestore = redefineMethods(classToMock, typeToMock); return null; } @Nullable private Set> redefineMethods(@NotNull Class realClass, @Nullable ParameterizedType mockedType) { return Startup.initializing ? null : new MockClassSetup(realClass, mockedType, this, null).redefineMethods(); } @NotNull private T createMockInstanceForMultipleInterfaces(@NotNull 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 - 2024 Weber Informatics LLC | Privacy Policy