Remove hard configuration validation from SpringClassRule/MethodRule

Issue: SPR-16967
This commit is contained in:
Juergen Hoeller 2018-06-28 13:36:43 +02:00
parent 08e1c8cfaf
commit b0ece0e967
2 changed files with 5 additions and 85 deletions

View File

@ -16,16 +16,11 @@
package org.springframework.test.context.junit4.rules; package org.springframework.test.context.junit4.rules;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.junit.Rule;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import org.junit.runner.Description; import org.junit.runner.Description;
import org.junit.runners.model.Statement; import org.junit.runners.model.Statement;
@ -35,7 +30,6 @@ import org.springframework.test.context.junit4.statements.ProfileValueChecker;
import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks; import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks;
import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks; import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/** /**
* {@code SpringClassRule} is a custom JUnit {@link TestRule} that supports * {@code SpringClassRule} is a custom JUnit {@link TestRule} that supports
@ -95,13 +89,7 @@ public class SpringClassRule implements TestRule {
/** /**
* Cache of {@code TestContextManagers} keyed by test class. * Cache of {@code TestContextManagers} keyed by test class.
*/ */
private static final Map<Class<?>, TestContextManager> testContextManagerCache = private static final Map<Class<?>, TestContextManager> testContextManagerCache = new ConcurrentHashMap<>(64);
new ConcurrentHashMap<>(64);
static {
Assert.state(ClassUtils.isPresent("org.junit.internal.Throwables", SpringClassRule.class.getClassLoader()),
"SpringClassRule requires JUnit 4.12 or higher.");
}
/** /**
@ -133,7 +121,6 @@ public class SpringClassRule implements TestRule {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Applying SpringClassRule to test class [" + testClass.getName() + "]"); logger.debug("Applying SpringClassRule to test class [" + testClass.getName() + "]");
} }
validateSpringMethodRuleConfiguration(testClass);
TestContextManager testContextManager = getTestContextManager(testClass); TestContextManager testContextManager = getTestContextManager(testClass);
Statement statement = base; Statement statement = base;
@ -176,37 +163,12 @@ public class SpringClassRule implements TestRule {
return new TestContextManagerCacheEvictor(next, testClass); return new TestContextManagerCacheEvictor(next, testClass);
} }
/**
* Throw an {@link IllegalStateException} if the supplied {@code testClass}
* does not declare a {@code public SpringMethodRule} field that is
* annotated with {@code @Rule}.
*/
private static void validateSpringMethodRuleConfiguration(Class<?> testClass) {
Field ruleField = findSpringMethodRuleField(testClass).orElseThrow(() ->
new IllegalStateException(String.format(
"Failed to find 'public SpringMethodRule' field in test class [%s]. " +
"Consult the javadoc for SpringClassRule for details.", testClass.getName())));
Assert.state(ruleField.isAnnotationPresent(Rule.class), () -> String.format(
"SpringMethodRule field [%s] must be annotated with JUnit's @Rule annotation. " +
"Consult the javadoc for SpringClassRule for details.", ruleField));
}
private static Optional<Field> findSpringMethodRuleField(Class<?> testClass) {
return Arrays.stream(testClass.getFields())
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.filter(field -> Modifier.isPublic(field.getModifiers()))
.filter(field -> SpringMethodRule.class.isAssignableFrom(field.getType()))
.findFirst();
}
/** /**
* Get the {@link TestContextManager} associated with the supplied test class. * Get the {@link TestContextManager} associated with the supplied test class.
* @param testClass the test class to be managed; never {@code null} * @param testClass the test class to be managed; never {@code null}
*/ */
static TestContextManager getTestContextManager(Class<?> testClass) { static TestContextManager getTestContextManager(Class<?> testClass) {
Assert.notNull(testClass, "testClass must not be null"); Assert.notNull(testClass, "Test Class must not be null");
return testContextManagerCache.computeIfAbsent(testClass, TestContextManager::new); return testContextManagerCache.computeIfAbsent(testClass, TestContextManager::new);
} }
@ -217,7 +179,6 @@ public class SpringClassRule implements TestRule {
private final Class<?> testClass; private final Class<?> testClass;
TestContextManagerCacheEvictor(Statement next, Class<?> testClass) { TestContextManagerCacheEvictor(Statement next, Class<?> testClass) {
this.next = next; this.next = next;
this.testClass = testClass; this.testClass = testClass;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,14 +16,10 @@
package org.springframework.test.context.junit4.rules; package org.springframework.test.context.junit4.rules;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.junit.ClassRule;
import org.junit.rules.MethodRule; import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement; import org.junit.runners.model.Statement;
@ -35,9 +31,6 @@ import org.springframework.test.context.junit4.statements.RunBeforeTestMethodCal
import org.springframework.test.context.junit4.statements.RunPrepareTestInstanceCallbacks; import org.springframework.test.context.junit4.statements.RunPrepareTestInstanceCallbacks;
import org.springframework.test.context.junit4.statements.SpringFailOnTimeout; import org.springframework.test.context.junit4.statements.SpringFailOnTimeout;
import org.springframework.test.context.junit4.statements.SpringRepeat; import org.springframework.test.context.junit4.statements.SpringRepeat;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/** /**
* {@code SpringMethodRule} is a custom JUnit 4 {@link MethodRule} that * {@code SpringMethodRule} is a custom JUnit 4 {@link MethodRule} that
@ -103,11 +96,6 @@ public class SpringMethodRule implements MethodRule {
private static final Log logger = LogFactory.getLog(SpringMethodRule.class); private static final Log logger = LogFactory.getLog(SpringMethodRule.class);
static {
Assert.state(ClassUtils.isPresent("org.junit.internal.Throwables", SpringMethodRule.class.getClassLoader()),
"SpringMethodRule requires JUnit 4.12 or higher.");
}
/** /**
* Apply <em>instance-level</em> and <em>method-level</em> features of * Apply <em>instance-level</em> and <em>method-level</em> features of
@ -143,7 +131,6 @@ public class SpringMethodRule implements MethodRule {
logger.debug("Applying SpringMethodRule to test method [" + testMethod + "]"); logger.debug("Applying SpringMethodRule to test method [" + testMethod + "]");
} }
Class<?> testClass = testInstance.getClass(); Class<?> testClass = testInstance.getClass();
validateSpringClassRuleConfiguration(testClass);
TestContextManager testContextManager = SpringClassRule.getTestContextManager(testClass); TestContextManager testContextManager = SpringClassRule.getTestContextManager(testClass);
Statement statement = base; Statement statement = base;
@ -182,8 +169,8 @@ public class SpringMethodRule implements MethodRule {
* Wrap the supplied {@link Statement} with a {@code RunPrepareTestInstanceCallbacks} statement. * Wrap the supplied {@link Statement} with a {@code RunPrepareTestInstanceCallbacks} statement.
* @see RunPrepareTestInstanceCallbacks * @see RunPrepareTestInstanceCallbacks
*/ */
private Statement withTestInstancePreparation(Statement next, Object testInstance, private Statement withTestInstancePreparation(
TestContextManager testContextManager) { Statement next, Object testInstance, TestContextManager testContextManager) {
return new RunPrepareTestInstanceCallbacks(next, testInstance, testContextManager); return new RunPrepareTestInstanceCallbacks(next, testInstance, testContextManager);
} }
@ -216,32 +203,4 @@ public class SpringMethodRule implements MethodRule {
return new ProfileValueChecker(next, testInstance.getClass(), testMethod); return new ProfileValueChecker(next, testInstance.getClass(), testMethod);
} }
/**
* Throw an {@link IllegalStateException} if the supplied {@code testClass}
* does not declare a {@code public static final SpringClassRule} field
* that is annotated with {@code @ClassRule}.
*/
private static SpringClassRule validateSpringClassRuleConfiguration(Class<?> testClass) {
Field ruleField = findSpringClassRuleField(testClass).orElseThrow(() ->
new IllegalStateException(String.format(
"Failed to find 'public static final SpringClassRule' field in test class [%s]. " +
"Consult the javadoc for SpringClassRule for details.", testClass.getName())));
Assert.state(ruleField.isAnnotationPresent(ClassRule.class), () -> String.format(
"SpringClassRule field [%s] must be annotated with JUnit's @ClassRule annotation. " +
"Consult the javadoc for SpringClassRule for details.", ruleField));
Object result = ReflectionUtils.getField(ruleField, null);
Assert.state(result instanceof SpringClassRule, "SpringClassRule field mismatch");
return (SpringClassRule) result;
}
private static Optional<Field> findSpringClassRuleField(Class<?> testClass) {
return Arrays.stream(testClass.getFields())
.filter(ReflectionUtils::isPublicStaticFinal)
.filter(field -> SpringClassRule.class.isAssignableFrom(field.getType()))
.findFirst();
}
} }