|
16 | 16 |
|
17 | 17 | package org.springframework.test.context.junit.jupiter;
|
18 | 18 |
|
| 19 | +import java.lang.reflect.AnnotatedElement; |
19 | 20 | import java.lang.reflect.Constructor;
|
20 | 21 | import java.lang.reflect.Executable;
|
21 | 22 | import java.lang.reflect.Method;
|
22 | 23 | import java.lang.reflect.Parameter;
|
| 24 | +import java.util.Optional; |
23 | 25 |
|
| 26 | +import org.apache.commons.logging.Log; |
| 27 | +import org.apache.commons.logging.LogFactory; |
24 | 28 | import org.junit.jupiter.api.extension.AfterAllCallback;
|
25 | 29 | import org.junit.jupiter.api.extension.AfterEachCallback;
|
26 | 30 | import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
|
27 | 31 | import org.junit.jupiter.api.extension.BeforeAllCallback;
|
28 | 32 | import org.junit.jupiter.api.extension.BeforeEachCallback;
|
29 | 33 | import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
|
| 34 | +import org.junit.jupiter.api.extension.ConditionEvaluationResult; |
| 35 | +import org.junit.jupiter.api.extension.ContainerExecutionCondition; |
30 | 36 | import org.junit.jupiter.api.extension.ContainerExtensionContext;
|
31 | 37 | import org.junit.jupiter.api.extension.ExtensionContext;
|
32 | 38 | import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
33 | 39 | import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
34 | 40 | import org.junit.jupiter.api.extension.ParameterContext;
|
35 | 41 | import org.junit.jupiter.api.extension.ParameterResolver;
|
| 42 | +import org.junit.jupiter.api.extension.TestExecutionCondition; |
36 | 43 | import org.junit.jupiter.api.extension.TestExtensionContext;
|
37 | 44 | import org.junit.jupiter.api.extension.TestInstancePostProcessor;
|
38 | 45 |
|
39 | 46 | import org.springframework.beans.factory.annotation.Autowired;
|
| 47 | +import org.springframework.beans.factory.config.BeanExpressionContext; |
| 48 | +import org.springframework.beans.factory.config.BeanExpressionResolver; |
| 49 | +import org.springframework.beans.factory.config.ConfigurableBeanFactory; |
40 | 50 | import org.springframework.context.ApplicationContext;
|
| 51 | +import org.springframework.context.ConfigurableApplicationContext; |
41 | 52 | import org.springframework.core.annotation.AnnotatedElementUtils;
|
42 | 53 | import org.springframework.test.context.TestContextManager;
|
43 | 54 | import org.springframework.util.Assert;
|
|
50 | 61 | * {@code @ExtendWith(SpringExtension.class)}.
|
51 | 62 | *
|
52 | 63 | * @author Sam Brannen
|
| 64 | + * @author Tadaya Tsuyukubo |
53 | 65 | * @since 5.0
|
54 | 66 | * @see org.springframework.test.context.junit.jupiter.SpringJUnitConfig
|
55 | 67 | * @see org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig
|
56 | 68 | * @see org.springframework.test.context.TestContextManager
|
| 69 | + * @see DisabledIf |
57 | 70 | */
|
58 | 71 | public class SpringExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor,
|
59 | 72 | BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback,
|
60 |
| - ParameterResolver { |
| 73 | + ParameterResolver, |
| 74 | + ContainerExecutionCondition, TestExecutionCondition { |
61 | 75 |
|
62 | 76 | /**
|
63 | 77 | * {@link Namespace} in which {@code TestContextManagers} are stored, keyed
|
64 | 78 | * by test class.
|
65 | 79 | */
|
66 | 80 | private static final Namespace namespace = Namespace.create(SpringExtension.class);
|
67 | 81 |
|
| 82 | + private static final ConditionEvaluationResult TEST_ENABLED = ConditionEvaluationResult.enabled( |
| 83 | + "@DisabledIf condition didn't match"); |
| 84 | + |
| 85 | + private static final Log logger = LogFactory.getLog(SpringExtension.class); |
| 86 | + |
| 87 | + |
68 | 88 | /**
|
69 | 89 | * Delegates to {@link TestContextManager#beforeTestClass}.
|
70 | 90 | */
|
@@ -175,6 +195,61 @@ public Object resolve(ParameterContext parameterContext, ExtensionContext extens
|
175 | 195 | return ParameterAutowireUtils.resolveDependency(parameter, testClass, applicationContext);
|
176 | 196 | }
|
177 | 197 |
|
| 198 | + @Override |
| 199 | + public ConditionEvaluationResult evaluate(ContainerExtensionContext context) { |
| 200 | + return evaluateDisabledIf(context); |
| 201 | + } |
| 202 | + |
| 203 | + @Override |
| 204 | + public ConditionEvaluationResult evaluate(TestExtensionContext context) { |
| 205 | + return evaluateDisabledIf(context); |
| 206 | + } |
| 207 | + |
| 208 | + private ConditionEvaluationResult evaluateDisabledIf(ExtensionContext extensionContext) { |
| 209 | + Optional<AnnotatedElement> element = extensionContext.getElement(); |
| 210 | + if (!element.isPresent()) { |
| 211 | + return TEST_ENABLED; |
| 212 | + } |
| 213 | + |
| 214 | + DisabledIf disabledIf = AnnotatedElementUtils.findMergedAnnotation(element.get(), DisabledIf.class); |
| 215 | + if (disabledIf == null) { |
| 216 | + return TEST_ENABLED; |
| 217 | + } |
| 218 | + |
| 219 | + String condition = disabledIf.condition(); |
| 220 | + if (condition.trim().length() == 0) { |
| 221 | + return TEST_ENABLED; |
| 222 | + } |
| 223 | + |
| 224 | + ApplicationContext applicationContext = getApplicationContext(extensionContext); |
| 225 | + if (!(applicationContext instanceof ConfigurableApplicationContext)) { |
| 226 | + return TEST_ENABLED; |
| 227 | + } |
| 228 | + |
| 229 | + ConfigurableBeanFactory configurableBeanFactory = ((ConfigurableApplicationContext) applicationContext) |
| 230 | + .getBeanFactory(); |
| 231 | + BeanExpressionResolver expressionResolver = configurableBeanFactory.getBeanExpressionResolver(); |
| 232 | + BeanExpressionContext beanExpressionContext = new BeanExpressionContext(configurableBeanFactory, null); |
| 233 | + |
| 234 | + Object result = expressionResolver |
| 235 | + .evaluate(configurableBeanFactory.resolveEmbeddedValue(condition), beanExpressionContext); |
| 236 | + |
| 237 | + if (result == null || !Boolean.valueOf(result.toString())) { |
| 238 | + return TEST_ENABLED; |
| 239 | + } |
| 240 | + |
| 241 | + String reason = disabledIf.reason(); |
| 242 | + if (reason.trim().length() == 0) { |
| 243 | + String testTarget = extensionContext.getTestMethod().map(Method::getName) |
| 244 | + .orElseGet(() -> extensionContext.getTestClass().get().getSimpleName()); |
| 245 | + reason = String.format("%s is disabled. condition=%s", testTarget, condition); |
| 246 | + } |
| 247 | + |
| 248 | + logger.info(String.format("%s is disabled. reason=%s", element.get(), reason)); |
| 249 | + return ConditionEvaluationResult.disabled(reason); |
| 250 | + |
| 251 | + } |
| 252 | + |
178 | 253 | /**
|
179 | 254 | * Get the {@link ApplicationContext} associated with the supplied
|
180 | 255 | * {@code ExtensionContext}.
|
|
0 commit comments