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 mockit.internal.annotations.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
import mockit.internal.util.*;

/**
 * A mock-up for a class or interface, to be used in state-based unit tests or to provide a
 * fake implementation 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 such method should have a matching "real" 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 */ 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() { Type typeToMock = getTypeToMock(); 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 Type getTypeToMock() { Class currentClass = getClass(); do { Type superclass = currentClass.getGenericSuperclass(); if (superclass instanceof ParameterizedType) { return ((ParameterizedType) superclass).getActualTypeArguments()[0]; } else if (superclass == MockUp.class) { throw new IllegalArgumentException("No type to be mocked"); } currentClass = (Class) superclass; } while (true); } 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) { MockClassSetup setup = new MockClassSetup(realClass, mockedType, this, null); if (Startup.initializing) { setup.setUpStartupMock(); return null; } else { return setup.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) { 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 interface(s) to be mocked specified by the type parameter {@code T}, or * {@literal null} otherwise (ie, if a class was specified to be mocked). */ 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); classesToRestore = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy