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

mockit.integration.junit4.JUnit4TestRunnerDecorator 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.integration.junit4;

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

import org.junit.*;
import org.junit.runners.model.*;

import mockit.integration.*;
import mockit.internal.expectations.*;
import mockit.internal.faking.*;
import mockit.internal.state.*;
import static mockit.internal.util.StackTrace.*;

final class JUnit4TestRunnerDecorator extends TestRunnerDecorator
{
   @Nullable
   Object invokeExplosively(@Nonnull FakeInvocation invocation, @Nullable Object target, Object... params) throws Throwable {
      FrameworkMethod it = invocation.getInvokedInstance();
      assert it != null;

      // A @BeforeClass/@AfterClass method:
      if (target == null) {
         try {
            return executeClassMethod(invocation, params);
         }
         catch (Throwable t) {
            filterStackTrace(t);
            throw t;
         }
      }

      handleMockingOutsideTestMethods(target);

      // A @Before/@After method:
      if (it.getAnnotation(Test.class) == null) {
         if (shouldPrepareForNextTest && it.getAnnotation(Before.class) != null) {
            prepareToExecuteSetupMethod(target);
         }

         TestRun.setRunningIndividualTest(target);

         try {
            invocation.prepareToProceedFromNonRecursiveMock();
            return it.invokeExplosively(target, params);
         }
         catch (Throwable t) {
            //noinspection ThrowableNotThrown
            RecordAndReplayExecution.endCurrentReplayIfAny();
            filterStackTrace(t);
            throw t;
         }
         finally {
            if (it.getAnnotation(After.class) != null) {
               shouldPrepareForNextTest = true;
            }
         }
      }

      if (shouldPrepareForNextTest) {
         prepareForNextTest();
      }

      shouldPrepareForNextTest = true;

      try {
         executeTestMethod(invocation, target, params);
         return null; // it's a test method, therefore has void return type
      }
      catch (Throwable t) {
         filterStackTrace(t);
         throw t;
      }
      finally {
         TestRun.finishCurrentTestExecution();
      }
   }

   @Nullable
   private static Object executeClassMethod(@Nonnull FakeInvocation inv, @Nonnull Object[] params) throws Throwable {
      FrameworkMethod method = inv.getInvokedInstance();
      assert method != null;
      handleMockingOutsideTests(method);

      TestRun.clearCurrentTestInstance();
      inv.prepareToProceedFromNonRecursiveMock();

      return method.invokeExplosively(null, params);
   }

   private void prepareToExecuteSetupMethod(@Nonnull Object target) {
      discardTestLevelMockedTypes();
      prepareForNextTest();
      shouldPrepareForNextTest = false;
      createInstancesForTestedFieldsBeforeSetup(target);
   }

   private static void handleMockingOutsideTests(@Nonnull FrameworkMethod it) {
      Class testClass = it.getMethod().getDeclaringClass();

      TestRun.enterNoMockingZone();

      try {
         Class currentTestClass = TestRun.getCurrentTestClass();

         if (currentTestClass != null && testClass.isAssignableFrom(currentTestClass) && it.getAnnotation(AfterClass.class) != null) {
            cleanUpMocksFromPreviousTest();
         }

         if (it.getAnnotation(BeforeClass.class) != null) {
            updateTestClassState(null, testClass);
         }
      }
      finally {
         TestRun.exitNoMockingZone();
      }
   }

   private static void handleMockingOutsideTestMethods(@Nonnull Object target) {
      Class testClass = target.getClass();

      TestRun.enterNoMockingZone();

      try {
         updateTestClassState(target, testClass);
      }
      finally {
         TestRun.exitNoMockingZone();
      }
   }

   private static void executeTestMethod(
      @Nonnull FakeInvocation invocation, @Nonnull Object testInstance, @Nullable Object... parameters
   ) throws Throwable {
      SavePoint savePoint = new SavePoint();

      TestRun.setRunningIndividualTest(testInstance);

      FrameworkMethod it = invocation.getInvokedInstance();
      assert it != null;
      Method testMethod = it.getMethod();
      Throwable testFailure = null;
      boolean testFailureExpected = false;

      try {
         createInstancesForTestedFieldsFromBaseClasses(testInstance);
         Object[] annotatedParameters = createInstancesForAnnotatedParameters(testInstance, testMethod, parameters);
         createInstancesForTestedFields(testInstance);

         invocation.prepareToProceedFromNonRecursiveMock();

         Object[] params = annotatedParameters == null ? parameters : annotatedParameters;
         it.invokeExplosively(testInstance, params);
      }
      catch (Throwable thrownByTest) {
         testFailure = thrownByTest;
         Class expectedType = testMethod.getAnnotation(Test.class).expected();
         testFailureExpected = expectedType.isAssignableFrom(thrownByTest.getClass());
      }
      finally {
         concludeTestMethodExecution(savePoint, testFailure, testFailureExpected);
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy