Last active
August 29, 2015 13:57
-
-
Save thomasdarimont/9bf439fa3c48f110b49e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.jugsaar.meeting8.testing.junit.poc; | |
import org.junit.Assert; | |
import org.junit.ClassRule; | |
import org.junit.Test; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.test.context.ContextConfiguration; | |
import org.springframework.test.context.support.AnnotationConfigContextLoader; | |
import de.jugsaar.meeting8.testing.junit.poc.SpringContext.Use; | |
import de.jugsaar.meeting8.testing.junit.poc.SpringJunit4RunnerRuleTests.Nested.SpecialConfig; | |
@ContextConfiguration(loader = AnnotationConfigContextLoader.class) | |
public class SpringJunit4RunnerRuleTests { | |
@ClassRule public static SpringContext springContext = new SpringContext(); | |
@Autowired Foo foo; | |
@Test | |
public void test1_should_use_ConcreteFoo() { | |
Assert.assertNotNull(foo); | |
Assert.assertTrue(foo instanceof ConcreteFoo); | |
} | |
@Test | |
@Use(SpecialConfig.class) | |
public void test2_should_use_SpecialFoo() { | |
Assert.assertNotNull(foo); | |
Assert.assertTrue(foo instanceof SpecialFoo); | |
} | |
@Test | |
public void test3_should_use_ConcreteFoo() { | |
Assert.assertNotNull(foo); | |
Assert.assertTrue(foo instanceof ConcreteFoo); | |
} | |
static interface Foo {} | |
static class ConcreteFoo implements Foo {}; | |
static class SpecialFoo implements Foo {} | |
@Configuration | |
static class Config { | |
@Bean | |
public Foo foo() { | |
return new ConcreteFoo(); | |
} | |
} | |
// Not visible for the test directly | |
public static class Nested { | |
@Configuration | |
public static class SpecialConfig extends Config { | |
@Bean | |
public Foo foo() { | |
return new SpecialFoo(); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.jugsaar.meeting8.testing.junit.poc; | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.annotation.Target; | |
import java.lang.reflect.Field; | |
import org.junit.rules.TestRule; | |
import org.junit.runner.Description; | |
import org.junit.runner.notification.RunNotifier; | |
import org.junit.runners.model.InitializationError; | |
import org.junit.runners.model.Statement; | |
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
import org.springframework.test.context.TestContext; | |
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | |
import org.springframework.test.context.support.AbstractTestExecutionListener; | |
import org.springframework.util.ReflectionUtils; | |
public class SpringContext implements TestRule { | |
private Class<?> testClass; | |
private volatile boolean initilized; | |
public SpringContext() { | |
this(null); | |
} | |
public SpringContext(Class<?> testClass) { | |
this.testClass = testClass; | |
} | |
@Override | |
public Statement apply(final Statement base, Description description) { | |
if (initilized) { | |
return base; | |
} | |
initilized = true; | |
invokeSpringRunner(base, description); | |
return noop(); | |
} | |
private void invokeSpringRunner(final Statement base, Description description) { | |
try { | |
Field runNotifierField = ReflectionUtils.findField(base.getClass(), "val$notifier"); | |
ReflectionUtils.makeAccessible(runNotifierField); | |
Object runNotifier = ReflectionUtils.getField(runNotifierField, base); | |
ExtendedSpringJUnit4ClassRunner runner = new ExtendedSpringJUnit4ClassRunner( | |
this.testClass != null ? this.testClass : description.getTestClass()); | |
runner.run(RunNotifier.class.cast(runNotifier)); | |
} catch (InitializationError e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private Statement noop() { | |
return new Statement() { | |
@Override | |
public void evaluate() throws Throwable {} | |
}; | |
} | |
static class ExtendedSpringJUnit4ClassRunner extends SpringJUnit4ClassRunner { | |
public ExtendedSpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError { | |
super(clazz); | |
getTestContextManager().getTestExecutionListeners().add(new NestedContextTestExecutionListener()); | |
} | |
} | |
static class NestedContextTestExecutionListener extends AbstractTestExecutionListener { | |
@Override | |
public void beforeTestMethod(TestContext testContext) throws Exception { | |
Use use = testContext.getTestMethod().getAnnotation(Use.class); | |
if (use != null && use.value().length > 0) { | |
AnnotationConfigApplicationContext ctxt = new AnnotationConfigApplicationContext(); | |
ctxt.setParent(testContext.getApplicationContext()); | |
for (Class<?> additionalConfigClass : use.value()) { | |
ctxt.register(additionalConfigClass); | |
} | |
ctxt.refresh(); | |
ctxt.getAutowireCapableBeanFactory().autowireBean(testContext.getTestInstance()); | |
} | |
} | |
} | |
@Target(ElementType.METHOD) | |
@Retention(RetentionPolicy.RUNTIME) | |
public static @interface Use { | |
Class<?>[] value() default {}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment