io.mats3.spring.test.SpringInjectRulesAndExtensions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mats-spring-test Show documentation
Show all versions of mats-spring-test Show documentation
Mats^3 Spring-specific testing tools, for quickly firing up a test-harness using either JUnit or Jupiter (JUnit 5).
The newest version!
package io.mats3.spring.test;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
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 java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestExecutionListeners.MergeMode;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import io.mats3.spring.test.SpringInjectRulesAndExtensions.SpringInjectRulesAndExtensionsTestExecutionListener;
/**
* Use this Test Execution Listener to autowire JUnit Rules and Jupiter Extensions, i.e. so that any fields in the Rule
* or Extension annotated with @Inject or @Autowire will be autowired - typically needed for
* Rule_MatsEndpoint
and Extension_MatsEndpoint
.
*
* To use, just put this annotation on the test class. If that fails, typically because you are also employing a
* different TestExecutionListener, a fallback is to directly list the
* {@link SpringInjectRulesAndExtensionsTestExecutionListener} in the @TestExecutionListeners
annotation on
* the test class, as such:
*
*
* {@literal @}TestExecutionListeners(listeners = SpringInjectRulesAndExtensionsTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
*
*
* @author Kevin Mc Tiernan, 2020-11-03, [email protected]
* @author Endre Stølsvik 2020-11-24 23:16 - http://stolsvik.com/, [email protected]
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestExecutionListeners(listeners = SpringInjectRulesAndExtensionsTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
@Documented
public @interface SpringInjectRulesAndExtensions {
/**
* This {@link TestExecutionListener} finds all fields in the test class instance which is annotated with JUnit
* Rule
or JUnit 5 Jupiter RegisterExtension
, and runs
* beanFactory.autowireBean(fieldValue)
on them.
*/
class SpringInjectRulesAndExtensionsTestExecutionListener extends AbstractTestExecutionListener {
/**
* Performs dependency injection on Rule
and @RegisterExtension
fields in test-class
* as supplied by testContext.
*/
@Override
public void prepareTestInstance(TestContext testContext) {
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext()
.getAutowireCapableBeanFactory();
// Get all fields in test class annotated with @Rule or @RegisterExtension
Set testRuleFields = findFields(testContext.getTestClass(), "org.junit.Rule");
Set testExtensionFields = findFields(testContext.getTestClass(),
"org.junit.jupiter.api.extension.RegisterExtension");
Set allFields = new HashSet<>();
allFields.addAll(testRuleFields);
allFields.addAll(testExtensionFields);
// Use bean factory to autowire all extensions
for (Field testField : allFields) {
try {
// We need to set this accessible, even for public fields, as Java 17s access controls will
// prevent access otherwise.
testField.setAccessible(true);
Object ruleObject = testField.get(testContext.getTestInstance());
beanFactory.autowireBean(ruleObject);
}
catch (Exception e) {
throw new AssertionError("Failed read field [" + testField + "] in [" + testField.getClass() + "],"
+ " unable to autowire it as a bean in test class [" + testContext.getTestClass() + "]", e);
}
}
}
/**
* Find all fields in class with given annotation. Amended from StackOverflow, inspired by Apache Commons Lang.
*
* https://stackoverflow.com/a/29766135
*/
@SuppressWarnings("unchecked")
protected static Set findFields(Class> clazz, String annotationClassName) {
try {
Class extends Annotation> annotationClass = (Class extends Annotation>) Class.forName(
annotationClassName);
Set set = new HashSet<>();
Class> c = clazz;
while (c != null) {
for (Field field : c.getDeclaredFields()) {
if (field.isAnnotationPresent(annotationClass)) {
set.add(field);
}
}
c = c.getSuperclass();
}
return set;
}
catch (ClassNotFoundException e) {
return Collections.emptySet();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy