Browse Source
This commit introduces @DisabledInAotMode in the TestContext framework to support the following use cases. - Disabling AOT build-time processing of a test ApplicationContext -- applicable to any testing framework (JUnit 4, JUnit Jupiter, etc.). - Disabling an entire test class or a single test method at run time when the test suite is run with AOT optimizations enabled -- only applicable to JUnit Jupiter based tests. Closes gh-30834pull/31445/head
10 changed files with 384 additions and 40 deletions
@ -0,0 +1,62 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2023 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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 org.springframework.test.context.aot; |
||||||
|
|
||||||
|
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 org.junit.jupiter.api.condition.DisabledIf; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code @DisabledInAotMode} signals that an annotated test class is <em>disabled</em> |
||||||
|
* in Spring AOT (ahead-of-time) mode, which means that the {@code ApplicationContext} |
||||||
|
* for the test class will not be processed for AOT optimizations at build time. |
||||||
|
* |
||||||
|
* <p>If a test class is annotated with {@code @DisabledInAotMode}, all other test |
||||||
|
* classes which specify configuration to load the same {@code ApplicationContext} |
||||||
|
* must also be annotated with {@code @DisabledInAotMode}. Failure to annotate |
||||||
|
* all such test classes will result in a exception, either at build time or |
||||||
|
* run time. |
||||||
|
* |
||||||
|
* <p>When used with JUnit Jupiter based tests, {@code @DisabledInAotMode} also |
||||||
|
* signals that the annotated test class or test method is <em>disabled</em> when |
||||||
|
* running the test suite in Spring AOT mode. When applied at the class level, |
||||||
|
* all test methods within that class will be disabled. In this sense, |
||||||
|
* {@code @DisabledInAotMode} has semantics similar to those of JUnit Jupiter's |
||||||
|
* {@link org.junit.jupiter.api.condition.DisabledInNativeImage @DisabledInNativeImage} |
||||||
|
* annotation. |
||||||
|
* |
||||||
|
* <p>This annotation may be used as a meta-annotation in order to create a |
||||||
|
* custom <em>composed annotation</em> that inherits the semantics of this |
||||||
|
* annotation. |
||||||
|
* |
||||||
|
* @author Sam Brannen |
||||||
|
* @since 6.1 |
||||||
|
* @see org.springframework.aot.AotDetector#useGeneratedArtifacts() AotDetector.useGeneratedArtifacts() |
||||||
|
* @see org.junit.jupiter.api.condition.EnabledInNativeImage @EnabledInNativeImage |
||||||
|
* @see org.junit.jupiter.api.condition.DisabledInNativeImage @DisabledInNativeImage |
||||||
|
*/ |
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD}) |
||||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||||
|
@Documented |
||||||
|
@DisabledIf(value = "org.springframework.aot.AotDetector#useGeneratedArtifacts", |
||||||
|
disabledReason = "Disabled in Spring AOT mode") |
||||||
|
public @interface DisabledInAotMode { |
||||||
|
} |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2023 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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 org.springframework.test.context.aot.samples.basic; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import org.springframework.aot.AotDetector; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.test.context.aot.DisabledInAotMode; |
||||||
|
import org.springframework.test.context.aot.TestContextAotGenerator; |
||||||
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code @DisabledInAotMode} test class which verifies that the application context |
||||||
|
* for the test class is skipped during AOT processing. |
||||||
|
* |
||||||
|
* @author Sam Brannen |
||||||
|
* @since 6.1 |
||||||
|
*/ |
||||||
|
@SpringJUnitConfig |
||||||
|
@DisabledInAotMode |
||||||
|
public class DisabledInAotProcessingTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
void disabledInAotMode(@Autowired String enigma) { |
||||||
|
assertThat(AotDetector.useGeneratedArtifacts()).as("Should be disabled in AOT mode").isFalse(); |
||||||
|
assertThat(enigma).isEqualTo("puzzle"); |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration |
||||||
|
static class Config { |
||||||
|
|
||||||
|
@Bean |
||||||
|
String enigma() { |
||||||
|
return "puzzle"; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
static BeanFactoryPostProcessor bfppBrokenDuringAotProcessing() { |
||||||
|
boolean runningDuringAotProcessing = StackWalker.getInstance().walk(stream -> |
||||||
|
stream.anyMatch(stackFrame -> stackFrame.getClassName().equals(TestContextAotGenerator.class.getName()))); |
||||||
|
|
||||||
|
return beanFactory -> Assert.state(!runningDuringAotProcessing, "Should not be used during AOT processing"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2023 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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 org.springframework.test.context.aot.samples.basic; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import org.springframework.aot.AotDetector; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.test.context.TestPropertySource; |
||||||
|
import org.springframework.test.context.aot.DisabledInAotMode; |
||||||
|
import org.springframework.test.context.aot.samples.common.DefaultMessageService; |
||||||
|
import org.springframework.test.context.aot.samples.common.MessageService; |
||||||
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code @DisabledInAotMode} class-level tests. |
||||||
|
* |
||||||
|
* <p>This test class differs from {@link DisabledInAotProcessingTests} whose |
||||||
|
* {@code ApplicationContext} will simply fail during AOT processing. Whereas, |
||||||
|
* the {@code ApplicationContext} for this test class can be properly processed |
||||||
|
* for AOT optimizations, but we want to ensure that we can also disable such a |
||||||
|
* test class in AOT mode if desired. |
||||||
|
* |
||||||
|
* @author Sam Brannen |
||||||
|
* @since 6.1 |
||||||
|
* @see DisabledInAotRuntimeMethodLevelTests |
||||||
|
* @see DisabledInAotProcessingTests |
||||||
|
*/ |
||||||
|
@SpringJUnitConfig |
||||||
|
@TestPropertySource(properties = "disabledInAotMode = class-level") |
||||||
|
@DisabledInAotMode |
||||||
|
public class DisabledInAotRuntimeClassLevelTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
void test(@Autowired ApplicationContext context, @Autowired MessageService messageService, |
||||||
|
@Value("${disabledInAotMode}") String disabledInAotMode) { |
||||||
|
|
||||||
|
assertThat(AotDetector.useGeneratedArtifacts()).as("Should be disabled in AOT mode").isFalse(); |
||||||
|
assertThat(messageService.generateMessage()).isEqualTo("Hello, AOT!"); |
||||||
|
assertThat(disabledInAotMode).isEqualTo("class-level"); |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false) |
||||||
|
static class BasicTestConfiguration { |
||||||
|
|
||||||
|
@Bean |
||||||
|
MessageService defaultMessageService() { |
||||||
|
return new DefaultMessageService(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2023 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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 org.springframework.test.context.aot.samples.basic; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import org.springframework.aot.AotDetector; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.test.context.TestPropertySource; |
||||||
|
import org.springframework.test.context.aot.DisabledInAotMode; |
||||||
|
import org.springframework.test.context.aot.samples.common.DefaultMessageService; |
||||||
|
import org.springframework.test.context.aot.samples.common.MessageService; |
||||||
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code @DisabledInAotMode} method-level tests. |
||||||
|
* |
||||||
|
* <p>The {@code ApplicationContext} will still be processed for AOT optimizations |
||||||
|
* and used for the {@link #test} method (in standard JVM mode and in AOT mode), |
||||||
|
* but the {@link #disabledInAotMode()} method will not be executed in AOT mode. |
||||||
|
* |
||||||
|
* @author Sam Brannen |
||||||
|
* @since 6.1 |
||||||
|
* @see DisabledInAotRuntimeClassLevelTests |
||||||
|
* @see DisabledInAotProcessingTests |
||||||
|
*/ |
||||||
|
@SpringJUnitConfig |
||||||
|
@TestPropertySource(properties = "disabledInAotMode = method-level") |
||||||
|
public class DisabledInAotRuntimeMethodLevelTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
void test(@Autowired ApplicationContext context, @Autowired MessageService messageService, |
||||||
|
@Value("${disabledInAotMode}") String disabledInAotMode) { |
||||||
|
|
||||||
|
assertThat(messageService.generateMessage()).isEqualTo("Hello, AOT!"); |
||||||
|
assertThat(disabledInAotMode).isEqualTo("method-level"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@DisabledInAotMode |
||||||
|
void disabledInAotMode() { |
||||||
|
assertThat(AotDetector.useGeneratedArtifacts()).as("Should be disabled in AOT mode").isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false) |
||||||
|
static class BasicTestConfiguration { |
||||||
|
|
||||||
|
@Bean |
||||||
|
MessageService defaultMessageService() { |
||||||
|
return new DefaultMessageService(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue