Java tutorial
/* * Copyright 2015 Sharmarke Aden <saden1 at gmail.org>. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.fitbur.jestify.junit.spring; import com.fitbur.jestify.api.Cut; import com.fitbur.jestify.core.TestContext; import com.fitbur.jestify.core.analyzer.CutAnalyzer; import com.fitbur.jestify.core.analyzer.TesAnalyzer; import com.fitbur.jestify.core.descriptor.TestDescriptor; import static com.google.common.base.Preconditions.checkState; import java.lang.reflect.Field; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static java.util.stream.Collectors.toSet; import static java.util.stream.Stream.of; import org.junit.internal.AssumptionViolatedException; import org.junit.internal.runners.model.EachTestNotifier; import org.junit.runner.Description; import static org.junit.runner.Description.createTestDescription; import org.junit.runner.notification.RunNotifier; import org.junit.runner.notification.StoppedByUserException; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; import org.objectweb.asm.ClassReader; import static org.objectweb.asm.ClassReader.EXPAND_FRAMES; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * * @author Sharmarke Aden <saden1 at gmail.org> */ public class IntegrationTestRunner extends BlockJUnit4ClassRunner { Map<Class, TestDescriptor> testClassContexts = new ConcurrentHashMap<>(); Map<Class, AnnotationConfigApplicationContext> applicationContexts = new ConcurrentHashMap<>(); private RunNotifier notifier; /** * Create a new test runner instance for the class under test. * * @param testClass the test class type * @throws InitializationError thrown if the test class is malformed. */ public IntegrationTestRunner(Class<?> testClass) throws InitializationError { super(testClass); } /** * Describe the test class. * * @return */ @Override public Description getDescription() { TestClass testClass = getTestClass(); Class<?> javaClass = testClass.getJavaClass(); String name = javaClass.getSimpleName(); return createTestDescription(javaClass, name, testClass.getAnnotations()); } @Override protected Object createTest() throws Exception { try { TestClass testClass = getTestClass(); Class<?> javaClass = testClass.getJavaClass(); String name = javaClass.getSimpleName(); TestDescriptor testDescriptor = testClassContexts.computeIfAbsent(javaClass, p -> { Object instance; try { instance = super.createTest(); TestContext context = new TestContext(name, javaClass, instance); Set<Field> candidatesFields = of(javaClass.getDeclaredFields()).parallel() .filter(f -> f.isAnnotationPresent(Cut.class)).collect(toSet()); if (candidatesFields.isEmpty()) { checkState(false, "Class under test not defined in %s. " + "Please annotated a single field with @Cut.", name); } else if (candidatesFields.size() != 1) { checkState(false, "Found more than one class under test in %s. " + "Please annotated only a single field with @Cut.", name); } Field cutField = candidatesFields.iterator().next(); ClassReader testReader = new ClassReader(javaClass.getName()); ClassReader cutReader = new ClassReader(cutField.getType().getName()); testReader.accept(new TesAnalyzer(context), EXPAND_FRAMES); cutReader.accept(new CutAnalyzer(context), EXPAND_FRAMES); return new TestDescriptor(instance, context); } catch (Exception e) { throw new RuntimeException(e); } }); AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(); appContext.setAllowBeanDefinitionOverriding(true); appContext.setId(name); appContext.setDisplayName(name); Object instance = testDescriptor.getInstance(); TestContext context = testDescriptor.getContext(); IntegrationTestReifier reifier = new IntegrationTestReifier(appContext, instance); IntegrationTestCreator integrationTestCreator = new IntegrationTestCreator(context, reifier, appContext); integrationTestCreator.create(); applicationContexts.put(javaClass, appContext); return instance; } catch (IllegalStateException e) { notifier.pleaseStop(); throw e; } } @Override public void run(RunNotifier notifier) { this.notifier = notifier; Description description = getDescription(); TestClass testClass = getTestClass(); Class<?> javaClass = testClass.getJavaClass(); String name = javaClass.getSimpleName(); IntegrationTestRunListener listener = new IntegrationTestRunListener(name, testClassContexts, applicationContexts); notifier.addListener(listener); EachTestNotifier testNotifier = new EachTestNotifier(notifier, description); try { Statement statement = classBlock(notifier); statement.evaluate(); // invoke here the run started method notifier.fireTestRunStarted(description); } catch (AssumptionViolatedException e) { testNotifier.fireTestIgnored(); } catch (StoppedByUserException e) { throw e; } catch (Throwable e) { testNotifier.addFailure(e); } } }