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

mockit.MockUp Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains mocking/faking APIs and a code coverage tool, 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.49
Show newest version
/*
 * Copyright (c) 2006 JMockit developers
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit;

import java.lang.reflect.*;
import javax.annotation.*;
import static java.lang.reflect.Modifier.*;

import mockit.internal.classGeneration.*;
import mockit.internal.faking.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;

/**
 * A base class used in the creation of a fake for an external type, which is usually a class from some library or component used
 * from the internal codebase of the system under test (SUT).
 * Such fake classes can be used as fake implementations for use in unit or integration tests.
 * For example:
 * 
 * public final class FakeSystem extends MockUp<System> {
 *    @Mock public static long nanoTime() { return 123L; }
 * }
 * 
* One or more fake methods annotated {@linkplain Mock as such} must be defined in the concrete subclass. * Each @Mock method should have a matching method or constructor in the faked class. * At runtime, the execution of a faked method/constructor will get redirected to the corresponding fake method. *

* When the type to be faked is specified indirectly through a {@linkplain TypeVariable type variable}, then that type is taken as a base * type whose concrete implementation classes should also get faked. * Example: *

 * @Test
 * public <BC extends SomeBaseClass> void someTest() {
 *     new MockUp<BC>() {
 *        @Mock int someMethod(int i) { return i + 1; }
 *     };
 *
 *     int i = new AConcreteSubclass().someMethod(1);
 *     assertEquals(2, i);
 * }
 * 
* * @param specifies the type to be faked; if a type variable is used, then all implementation classes extending or implementing that base type * are also faked; if the type argument itself is a parameterized type, then only its raw type is considered * * @see #MockUp() * @see #MockUp(Class) * @see #onTearDown() * @see #targetType * @see Tutorial */ public abstract class MockUp { static { Startup.verifyInitialization(); } /** * Holds the class or generic type targeted by this fake instance. */ @Nonnull protected final Type targetType; /** * Applies the {@linkplain Mock fake methods} defined in the concrete subclass to the class specified through the * type parameter. */ protected MockUp() { MockUp previousFake = findPreviouslyFakedClassIfFakeAlreadyApplied(); if (previousFake != null) { targetType = previousFake.targetType; return; } targetType = getTypeToFake(); Class classToFake = null; if (targetType instanceof Class) { //noinspection unchecked classToFake = (Class) targetType; } else if (targetType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) targetType; //noinspection unchecked classToFake = (Class) parameterizedType.getRawType(); } if (classToFake != null) { redefineClass(classToFake); } else { Type[] typesToFake = ((TypeVariable) targetType).getBounds(); if (typesToFake.length == 1) { new CaptureOfFakedImplementations(this, typesToFake[0]).apply(); } else { throw new UnsupportedOperationException("Unable to capture more than one base type at once"); } } } @Nullable private MockUp findPreviouslyFakedClassIfFakeAlreadyApplied() { FakeClasses fakeClasses = TestRun.getFakeClasses(); MockUp previousFake = fakeClasses.findPreviouslyAppliedFake(this); return previousFake; } @Nonnull private Type getTypeToFake() { Class currentClass = getClass(); do { Type superclass = currentClass.getGenericSuperclass(); if (superclass instanceof ParameterizedType) { return ((ParameterizedType) superclass).getActualTypeArguments()[0]; } if (superclass == MockUp.class) { throw new IllegalArgumentException("No target type"); } currentClass = (Class) superclass; } while (true); } private void redefineClass(@Nonnull Class classToFake) { if (!classToFake.isInterface()) { Class realClass = classToFake; if (isAbstract(classToFake.getModifiers())) { classToFake = new ConcreteSubclass(classToFake).generateClass(); } new FakeClassSetup(realClass, classToFake, targetType, this).redefineMethods(); } } /** * Applies the {@linkplain Mock fake methods} defined in the fake class to the given class. *

* In most cases, the {@linkplain #MockUp() constructor with no parameters} can be used. * This variation is useful when the type to be faked is not known at compile time. For example, it can be used with an {@linkplain Mock $advice} * method and the fakes system property in order to have an aspect-like fake implementation applicable to any class; it can then be * applied at the beginning of the test run with the desired target class being specified in the test run configuration. */ protected MockUp(@Nonnull Class targetClass) { targetType = targetClass; MockUp previousFake = findPreviouslyFakedClassIfFakeAlreadyApplied(); if (previousFake != null) { return; } if (!targetClass.isInterface()) { new FakeClassSetup(targetClass, this).redefineMethods(); } } /** * An empty method that can be overridden in a fake class that wants to be notified whenever the fake is automatically torn down. * Tear down happens when the fake goes out of scope: at the end of the test when applied inside a test, at the end of the test class when applied * before the test class, or at the end of the test run when applied through the "fakes" system property. *

* By default, this method does nothing. */ protected void onTearDown() {} }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy