https://docs.spring.io/spring-framework/reference/testing/annotations.html
本节介绍了在测试Spring应用程序时可以使用的注解。
标准注解支持
Spring TestContext Framework 的所有配置都支持以下具有标准语义的注解。请注意,这些注解并不特定于测试,并且可以在 Spring Framework 中的任何位置使用。
@Autowired
@Qualifier
@Value
@Resource
(jakarta.annotation
)如果JSR-250存在@ManagedBean
(jakarta.annotation
)如果JSR-250存在@Inject
(jakarta.inject
)如果JSR-330存在@Named
(jakarta.inject
)如果JSR-330存在@PersistenceContext
(jakarta.persistence
) 如果JPA存在@PersistenceUnit
(jakarta.persistence
) 如果JPA存在@Transactional
(org.springframework.transaction.annotation
),仅支持有限属性
在Spring TestContext Framework中,可以在ApplicationContext
中配置的任何应用程序组件上使用具有标准语义的@PostConstruct
和@PreDestroy
注解。然而,这些生命周期注解在实际测试类中的使用是有限制的。
如果一个测试类中的方法被@PostConstruct
注解,那么这个方法会在底层测试框架的任何前置方法(例如,使用JUnit Jupiter的@BeforeEach
注解的方法)之前运行,并且这适用于测试类中的每个测试方法。另一方面,如果一个测试类中的方法被@PreDestroy
注解,那么这个方法永远不会运行。因此,在测试类中,建议使用底层测试框架的测试生命周期回调,而不是@PostConstruct
和@PreDestroy
。
Spring测试注解
Spring框架提供了一系列Spring特有的注解,你可以与TestContext框架结合使用这些注解进行单元测试和集成测试。
Spring的测试注解包括以下几种:
@BootstrapWith
@ContextConfiguration
@WebAppConfiguration
@ContextHierarchy
@ContextCustomizerFactories
@ActiveProfiles
@TestPropertySource
@DynamicPropertySource
@DirtiesContext
@TestExecutionListeners
@RecordApplicationEvents
@Commit
@Rollback
@BeforeTransaction
@AfterTransaction
@Sql
@SqlConfig
@SqlMergeMode
@SqlGroup
@DisabledInAotMode
@BootstrapWith
@BootstrapWith
是一个类级别的注解,你可以使用它来配置 Spring TestContext Framework 的引导方式。具体来说,你可以使用 @BootstrapWith
来指定一个自定义的 TestContextBootstrapper
。
@ContextConfiguration
@ContextConfiguration
定义类级别的元数据,用于确定如何加载和配置用于集成测试的 ApplicationContext
。具体来说,@ContextConfiguration
声明了应用程序上下文资源的locations
或用于加载上下文的组件classes
。
资源位置通常是位于类路径中的 XML 配置文件或 Groovy 脚本,而组件类通常是带有 @Configuration
注解的类。然而,资源位置也可以引用文件系统中的文件和脚本,组件类也可以是带有 @Component
注解的类、带有 @Service
注解的类等。
以下示例展示了引用 XML 文件的 @ContextConfiguration
注解:
@ContextConfiguration("/test-config.xml")
class XmlApplicationContextTests {
// class body...
}
以下示例展示了引用一个类的 @ContextConfiguration
注解:
@ContextConfiguration(classes = TestConfig.class)
class ConfigClassApplicationContextTests {
// class body...
}
除了声明资源位置或组件类之外,你还可以使用 @ContextConfiguration
来声明 ApplicationContextInitializer
类。以下示例展示了这种情况:
@ContextConfiguration(initializers = CustomContextInitializer.class)
class ContextInitializerTests {
// class body...
}
你还可以选择使用 @ContextConfiguration
来声明 ContextLoader
策略。但请注意,你通常不需要显式配置加载器,因为默认加载器支持initializers
以及资源locations
或组件classes
。
以下示例同时使用了一个位置和一个加载器:
@ContextConfiguration(locations = "/test-context.xml", loader = CustomContextLoader.class)
class CustomLoaderXmlApplicationContextTests {
// class body...
}
@ContextConfiguration
提供支持继承资源位置或配置类,以及由超类或封闭类声明的上下文初始化器。
@WebAppConfiguration
@WebAppConfiguration
是一个类级别的注解,你可以使用它来声明一个集成测试应该加载的ApplicationContext
是一个WebApplicationContext
。仅仅在测试类上存在@WebAppConfiguration
就能确保为测试加载一个WebApplicationContext
,使用默认值"file:src/main/webapp
"作为web应用的根路径(即资源基本路径)。资源基本路径在幕后被用来创建一个MockServletContext
,它作为测试的WebApplicationContext
的ServletContext
。
以下示例展示了如何使用@WebAppConfiguration
注解:
@ContextConfiguration
@WebAppConfiguration
class WebAppTests {
// class body...
}
要覆盖默认值,可以使用隐式value
属性指定不同的基本资源路径。支持classpath:
和file:
资源前缀。如果没有提供资源前缀,则假定路径是文件系统资源。以下示例展示了如何指定类路径资源:
@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources")
class WebAppTests {
// class body...
}
请注意,@WebAppConfiguration
必须与@ContextConfiguration
结合使用,无论是在单个测试类中还是在测试类层次结构中。
@ContextHierarchy
@ContextHierarchy
是一个类级别的注解,用于为集成测试定义ApplicationContext
实例的层次结构。@ContextHierarchy
应该与一个或多个@ContextConfiguration
实例一起声明,每个实例都定义了上下文层次结构中的一个级别。以下示例演示了如何在单个测试类中使用@ContextHierarchy
(@ContextHierarchy
也可以在测试类层次结构中使用):
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class ContextHierarchyTests {
// class body...
}
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = AppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class WebIntegrationTests {
// class body...
}
如果需要在测试类层次结构中合并或覆盖上下文层次结构的给定级别的配置,你必须通过在每个相应级别的类层次结构中的@ContextConfiguration
的name
属性提供相同的值来显式命名该级别。
@ContextCustomizerFactories
@ContextCustomizerFactories
用于为特定测试类、其子类和嵌套类注册ContextCustomizerFactory
实现。
以下示例展示了如何注册两个ContextCustomizerFactory
实现:
@ContextConfiguration
@ContextCustomizerFactories({CustomContextCustomizerFactory.class, AnotherContextCustomizerFactory.class})
class CustomContextCustomizerFactoryTests {
// class body...
}
默认情况下,@ContextCustomizerFactories
支持从超类或外部类继承工厂。
@ActiveProfiles
@ActiveProfiles
是一个类级别的注解,用于声明在加载集成测试的 ApplicationContext
时应该激活哪些 bean 定义profile。
以下示例表明dev
profile 应该是激活的:
@ContextConfiguration
@ActiveProfiles("dev")
class DeveloperTests {
// class body...
}
以下示例表明dev
和integration
profile 都应该激活:
@ContextConfiguration
@ActiveProfiles({"dev", "integration"})
class DeveloperIntegrationTests {
// class body...
}
@ActiveProfiles
默认支持从超类或外部类继承激活的bean定义profile。你也可以通过实现自定义的ActiveProfilesResolver
并使用@ActiveProfiles
的resolver
属性来注册它,从而以编程方式解析激活的bean定义profile。
@TestPropertySource
@TestPropertySource
是一个类级别的注解,你可以使用它来配置属性文件的位置和内联属性,这些属性将被添加到为集成测试加载的ApplicationContext
的Environment
中的PropertySources
集合中。
以下示例展示了如何声明一个类路径下的属性文件:
@ContextConfiguration
@TestPropertySource("/test.properties")
class MyIntegrationTests {
// class body...
}
以下示例展示了如何声明内联属性:
@ContextConfiguration
@TestPropertySource(properties = { "timezone = GMT", "port: 4242" })
class MyIntegrationTests {
// class body...
}
@DynamicPropertySource
@DynamicPropertySource
是一个方法级别的注解,你可以使用它来注册动态属性,这些属性将被添加到为集成测试加载的ApplicationContext
的Environment
中的PropertySources
集合中。当你事先不知道属性的值时,动态属性非常有用——例如,如果属性由外部资源管理,比如Testcontainers项目管理的容器。
以下示例展示了如何注册一个动态属性:
@ContextConfiguration
class MyIntegrationTests {
static MyExternalServer server = // ...
@DynamicPropertySource
static void dynamicProperties(DynamicPropertyRegistry registry) {
registry.add("server.port", server::getPort);
}
// tests ...
}
@DirtiesContext
@DirtiesContext
表示在执行测试期间,底层的Spring ApplicationContext
已经被弄脏(即,测试以某种方式修改或损坏了它——例如,通过改变单例bean的状态),应该被关闭。当一个应用程序上下文被标记为脏时,它将从测试框架的缓存中移除并关闭。因此,对于任何后续需要具有相同配置元数据的上下文的测试,都将重建底层的Spring容器。
你可以在同一个类或类层次结构中,将@DirtiesContext
同时用作类级别和方法级别的注解。在这种情况下,ApplicationContext
将在任何此类注解方法之前或之后以及当前测试类之前或之后被标记为脏,具体取决于配置的methodMode
和classMode
。当在类级别和方法级别都声明了@DirtiesContext
时,将遵循两个注解配置的模式。例如,如果类模式设置为BEFORE_EACH_TEST_METHOD
,方法模式设置为AFTER_METHOD
,那么上下文将在给定的测试方法之前和之后都被标记为脏。
以下示例解释了在不同的配置场景下,上下文何时会被标记为脏:
- 在当前的测试类之前,当在一个类上声明时,如果该类的模式设置为
BEFORE_CLASS
。
@DirtiesContext(classMode = BEFORE_CLASS)
class FreshContextTests {
// some tests that require a new Spring container
}
- 在当前的测试类之后,当在一个类上声明时,如果该类的模式设置为
AFTER_CLASS
(即默认的类模式)。
@DirtiesContext
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
- 在当前测试类的每一个测试方法之前,当在一个类上声明时,如果该类的模式设置为
BEFORE_EACH_TEST_METHOD
。
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
class FreshContextTests {
// some tests that require a new Spring container
}
- 在当前测试类的每一个测试方法之后,当在一个类上声明时,如果该类的模式设置为
AFTER_EACH_TEST_METHOD
。
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
- 在当前测试之前,当在一个方法上声明时,如果该方法的模式设置为
BEFORE_METHOD
。
@DirtiesContext(methodMode = BEFORE_METHOD)
@Test
void testProcessWhichRequiresFreshAppCtx() {
// some logic that requires a new Spring container
}
- 在当前测试之后,当在一个方法上声明时,如果该方法的模式设置为
AFTER_METHOD
(即默认的方法模式)。
@DirtiesContext
@Test
void testProcessWhichDirtiesAppCtx() {
// some logic that results in the Spring container being dirtied
}
如果你在测试中使用@DirtiesContext
,并且其上下文被配置为具有@ContextHierarchy
的上下文层次结构的一部分,你可以使用hierarchyMode
标志来控制如何清除上下文缓存。默认情况下,会使用一种穷举算法来清除上下文缓存,包括当前级别以及所有其他与当前测试共享公共祖先上下文的上下文层次结构。所有驻留在公共祖先上下文的子层次结构中的ApplicationContext
实例都会从上下文缓存中移除并关闭。如果对于特定用例来说,穷举算法做得太过了,你可以指定更简单的当前级别算法,如下所示的例子。
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class BaseTests {
// class body...
}
class ExtendedTests extends BaseTests {
@Test
@DirtiesContext(hierarchyMode = CURRENT_LEVEL)
void test() {
// some logic that results in the child context being dirtied
}
}
@TestExecutionListeners
@TestExecutionListeners
用于为特定的测试类、其子类以及嵌套类注册监听器。如果你希望全局注册监听器,你应该通过自动发现机制来注册它。
下面的示例展示了如何注册两个TestExecutionListener
实现:
@ContextConfiguration
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
class CustomTestExecutionListenerTests {
// class body...
}
默认情况下,@TestExecutionListeners
提供从超类或封装类继承监听器的支持。
@RecordApplicationEvents
@RecordApplicationEvents
是一个类级别注解,用于指示Spring TestContext框架记录在单个测试执行过程中ApplicationContext
中发布的所有应用程序事件。
在测试中可以通过ApplicationEvents
API访问记录的事件。
@Commit
@Commit
表示事务测试方法的事务应在测试方法完成后提交。你可以将 @Commit
直接替换 @Rollback(false)
,以更明确地传达代码的意图。类似于 @Rollback
,@Commit
也可以声明为类级别或方法级别的注解。
下面的示例展示了如何使用 @Commit
注解:
@Commit
@Test
void testProcessWithoutRollback() {
// ...
}
@Rollback
@Rollback
表示在测试方法完成后,事务测试方法的事务是否应该回滚。如果为 true
,则事务会被回滚。否则,事务将被提交。即使在没有显式声明 @Rollbac
k 的情况下,Spring TestContext Framework 中的集成测试的回滚默认也为 true
。
当作为类级别注解声明时,@Rollback
定义了测试类层次结构中所有测试方法的默认回滚语义。当作为方法级别注解声明时,@Rollback
定义了特定测试方法的回滚语义,可能会覆盖类级别的 @Rollback
或 @Commit
语义。
下面的示例会导致测试方法的结果不被回滚(即,结果被提交到数据库):
@Rollback(false)
@Test
void testProcessWithoutRollback() {
// ...
}
@BeforeTransaction
@BeforeTransaction
表示在事务开始之前,应该运行被该注解标记的 void
方法。这个注解适用于那些已经通过使用 Spring 的 @Transactional
注解配置为在事务中运行的测试方法。@BeforeTransaction
方法不需要是 public
的,也可以在基于 Java 8 的接口默认方法上声明。
下面的例子展示了如何使用 @BeforeTransaction
注解:
@BeforeTransaction
void beforeTransaction() {
// logic to be run before a transaction is started
}
@AfterTransaction
@AfterTransaction
表示标注的 void
方法应该在事务结束后运行,这些测试方法通过使用 Spring 的 @Transactional
注解被配置为在事务中运行。@AfterTransaction
方法不要求必须是公共的,并且可以在基于 Java 8 的接口默认方法上声明。
@AfterTransaction
void afterTransaction() {
// logic to be run after a transaction has ended
}
@Sql
@Sql
注解用于标记测试类或测试方法,以配置在集成测试期间针对给定数据库运行的 SQL 脚本。下面的例子展示了如何使用它:
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
void userTest() {
// run code that relies on the test schema and test data
}
@SqlConfig
@SqlConfig
定义了用于确定如何解析和运行使用 @Sql
注解配置的 SQL 脚本的元数据。下面的例子展示了如何使用它:
@Test
@Sql(
scripts = "/test-user-data.sql",
config = @SqlConfig(commentPrefix = "`", separator = "@@")
)
void userTest() {
// run code that relies on the test data
}
@SqlMergeMode
@SqlMergeMode
用于标记测试类或测试方法,以配置是否将方法级别的 @Sql
声明与类级别的 @Sql
声明合并。如果在测试类或测试方法上没有声明 @SqlMergeMode
,则默认使用 OVERRIDE
合并模式。在 OVERRIDE
模式下,方法级别的 @Sql
声明将有效覆盖类级别的 @Sql
声明。
请注意,方法级别的 @SqlMergeMode
声明会覆盖类级别的声明。
下面的例子展示了如何在类级别使用 @SqlMergeMode
。
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
@SqlMergeMode(MERGE)
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
void standardUserProfile() {
// run code that relies on test data set 001
}
}
下面的例子展示了如何在方法级别使用 @SqlMergeMode
。
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
@SqlMergeMode(MERGE)
void standardUserProfile() {
// run code that relies on test data set 001
}
}
@SqlGroup
@SqlGroup
是一个容器注解,用于聚合多个 @Sql
注解。你可以原生地使用 @SqlGroup
来声明多个嵌套的 @Sql
注解,或者你可以结合 Java 8 对可重复注解的支持使用它,其中 @Sql
可以在同一个类或方法上声明多次,隐式生成这个容器注解。下面的例子展示了如何声明一个 SQL 组:
@Test
@SqlGroup({
@Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`")),
@Sql("/test-user-data.sql")
})
void userTest() {
// run code that uses the test schema and test data
}
@DisabledInAotMode
@DisabledInAotMode
表示在 Spring AOT(提前编译)模式下,被注解的测试类是禁用的,这意味着在构建时不会针对测试类的 ApplicationContext
进行 AOT 优化。
如果一个测试类被 @DisabledInAotMode
注解,所有其他指定加载同一 ApplicationContext
的测试类也必须用 @DisabledInAotMode
进行注解。如果没有对所有这样的测试类进行注解,将在构建时或运行时抛出异常。
当与基于 JUnit Jupiter 的测试一起使用时,@DisabledInAotMode
还表示在 Spring AOT 模式下运行测试套件时,被注解的测试类或测试方法是禁用的。当应用于类级别时,该类中的所有测试方法都将被禁用。在这个意义上,@DisabledInAotMode
的语义与 JUnit Jupiter 的 @DisabledInNativeImage
注解相似。
Spring JUnit 4 测试注解
以下注解仅在使用 SpringRunner,Spring 的 JUnit 4 规则,或 Spring 的 JUnit 4 支持类时受支持:
@IfProfileValue
@ProfileValueSourceConfiguration
@Timed
@Repeat
@IfProfileValue
@IfProfileValue
表示针对特定测试环境启用被注解的测试。如果配置的 ProfileValueSource
为提供的 name
返回匹配的value
,则启用该测试。否则,禁用该测试,并实际上忽略它。
可以在类级别、方法级别或两者同时使用 @IfProfileValue
。类级别的 @IfProfileValue
使用优先于该类或其子类中任何方法的方法级别使用。具体来说,如果一个测试在类级别和方法级别都被启用,则该测试被启用。缺少 @IfProfileValue
意味着测试被隐式启用。这与 JUnit 4 的 @Ignore
注解的语义类似,不同的是 @Ignore
的存在总是禁用测试。
下面的例子展示了一个带有 @IfProfileValue
注解的测试:
@IfProfileValue(name="java.vendor", value="Oracle Corporation")
@Test
public void testProcessWhichRunsOnlyOnOracleJvm() {
// some logic that should run only on Java VMs from Oracle Corporation
}
或者,你可以将 @IfProfileValue
配置为一个值列表(具有 OR
语义),以在 JUnit 4 环境中实现类似 TestNG 的测试组支持。考虑以下示例:
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}
为单元测试和集成测试运行此测试。
@ProfileValueSourceConfiguration
@ProfileValueSourceConfiguration
是一个类级别注解,用于指定在检索通过 @IfProfileValue
注解配置的profile 值时使用哪种类型的 ProfileValueSource
。如果测试中没有声明 @ProfileValueSourceConfiguration
,则默认使用 SystemProfileValueSource
。下面的例子展示了如何使用 @ProfileValueSourceConfiguration
:
@ProfileValueSourceConfiguration(CustomProfileValueSource.class)
public class CustomProfileValueSourceTests {
// class body...
}
@Timed
@Timed
表示被注解的测试方法必须在指定的时间段(以毫秒为单位)内完成执行。如果测试执行时间超过了指定的时间段,测试将失败。
时间段包括运行测试方法本身、测试的任何重复,以及任何设置或拆除测试夹具的时间。下面的例子展示了如何使用它:
@Timed(millis = 1000)
public void testProcessWithOneSecondTimeout() {
// some logic that should not take longer than 1 second to run
}
Spring 的 @Timed
注解与 JUnit 4 的 @Test(timeout=…)
支持具有不同的语义。具体来说,由于 JUnit 4 处理测试执行超时的方式(即在单独的线程中执行测试方法),@Test(timeout=…)
如果测试花费时间过长,会预先使测试失败。另一方面,Spring 的 @Timed
不会预先使测试失败,而是在测试完成后才判定失败。
@Repeat
@Repeat
表示被注解的测试方法必须重复运行。测试方法要运行的次数在注解中指定。
要重复的执行范围包括测试方法本身的执行以及任何设置或拆除测试夹具。当与 SpringMethodRule
一起使用时,范围还包括由 TestExecutionListener
实现对测试实例的准备。下面的例子展示了如何使用 @Repeat
注解:
@Repeat(10)
@Test
public void testProcessRepeatedly() {
// ...
}
Spring JUnit Jupiter 测试注解
以下注解在使用 SpringExtension
和 JUnit Jupiter(即 JUnit 5 中的编程模型)时受支持:
@SpringJUnitConfig
@SpringJUnitWebConfig
@TestConstructor
@NestedTestConfiguration
@EnabledIf
@DisabledIf
@DisabledInAotMode
@SpringJUnitConfig
@SpringJUnitConfig
是一个组合注解,它将 JUnit Jupiter 的 @ExtendWith(SpringExtension.class)
与 Spring TestContext Framework 的 @ContextConfiguration
结合在一起。它可以在类级别用作 @ContextConfiguration
的直接替代品。就配置选项而言,@ContextConfiguration
和 @SpringJUnitConfig
之间唯一的区别是,组件类可以在 @SpringJUnitConfig
中用 value
属性声明。
下面的例子展示了如何使用 @SpringJUnitConfig
注解指定一个配置类:
@SpringJUnitConfig(TestConfig.class)
class ConfigurationClassJUnitJupiterSpringTests {
// class body...
}
下面的例子展示了如何使用 @SpringJUnitConfig
注解指定配置文件的位置:
@SpringJUnitConfig(locations = "/test-config.xml")
class XmlJUnitJupiterSpringTests {
// class body...
}
@SpringJUnitWebConfig
@SpringJUnitWebConfig
是一个组合注解,它将 JUnit Jupiter 的 @ExtendWith(SpringExtension.class)
与 Spring TestContext Framework 的 @ContextConfiguration
和 @WebAppConfiguration
结合在一起。你可以将其用在类级别,作为 @ContextConfiguration
和 @WebAppConfiguration
的直接替代品。就配置选项而言,@ContextConfiguration
和 @SpringJUnitWebConfig
之间唯一的区别是,你可以通过使用 @SpringJUnitWebConfig
中的 value
属性声明组件类。此外,你只能通过使用 @SpringJUnitWebConf
ig 中的 resourcePath
属性来覆盖 @WebAppConfiguration
的 value
属性。
下面的例子展示了如何使用 @SpringJUnitWebConfig
注解指定一个配置类:
@SpringJUnitWebConfig(TestConfig.class)
class ConfigurationClassJUnitJupiterSpringWebTests {
// class body...
}
下面的例子展示了如何使用 @SpringJUnitWebConfig
注解指定配置文件的位置:
@SpringJUnitWebConfig(locations = "/test-config.xml")
class XmlJUnitJupiterSpringWebTests {
// class body...
}
@TestConstructor
@TestConstructor
是一个类型级别的注解,用于配置测试类构造函数的参数如何从测试的ApplicationContext
中的组件进行自动装配。
如果@TestConstructor
没有出现在测试类上,或者在元数据中出现,那么将使用默认的测试构造函数自动装配模式。如果构造函数上有局部声明的@Autowired
、@jakarta.inject.Inject
或@javax.inject.Inject
注解,那么这些注解将优先于@TestConstructor
和默认模式。
默认的测试构造函数自动装配模式可以通过将JVM系统属性spring.test.constructor.autowire.mode
设置为all
来更改。或者,也可以通过SpringProperties
机制设置默认模式。
自Spring框架5.3起,默认模式也可以配置为JUnit平台的配置参数。
如果没有设置spring.test.constructor.autowire.mode
属性,测试类构造函数将不会被自动装配。
自Spring框架5.2起,@TestConstructor
仅与JUnit Jupiter的SpringExtension
一起支持使用。请注意,SpringExtension
通常会自动注册——例如,当使用@SpringJUnitConfig
和@SpringJUnitWebConfig
注解或者来自Spring Boot Test的各种测试相关注解时。
@NestedTestConfiguration
@NestedTestConfiguration
是一个类型级别的注解,用于配置在内部测试类的封闭类层次结构中如何处理Spring测试配置注解。
如果测试类、其超类型层次结构或其封闭类层次结构中没有出现@NestedTestConfiguration
,或者在元数据中出现,那么将使用默认的封闭配置继承模式。
默认的封闭配置继承模式是INHERIT
,但可以通过将JVM系统属性spring.test.enclosing.configuration
设置为OVERRIDE
来更改。或者,也可以通过SpringProperties
机制设置默认模式。
Spring TestContext框架遵循以下注解的@NestedTestConfiguration
语义。
@BootstrapWith
@ContextConfiguration
@WebAppConfiguration
@ContextHierarchy
@ContextCustomizerFactories
@ActiveProfiles
@TestPropertySource
@DynamicPropertySource
@DirtiesContext
@TestExecutionListeners
@RecordApplicationEvents
@Transactional
@Commit
@Rollback
@Sql
@SqlConfig
@SqlMergeMode
@TestConstructor
@NestedTestConfiguration
的使用通常只在与JUnit Jupiter中的@Nested
测试类结合时才有意义;然而,可能还有其他支持Spring和嵌套测试类的测试框架使用这个注解。
@EnabledIf
@EnabledIf
用于表示,如果提供的表达式计算结果为true
,则标记的JUnit Jupiter测试类或测试方法将被启用并应该运行。具体来说,如果表达式计算结果为Boolean.TRUE
或等于true
(忽略大小写)的字符串,则测试被启用。当应用于类级别时,该类中的所有测试方法默认也会自动启用。
表达式可以是以下任意一种:
- Spring Expression Language(SpEL)表达式。例如:
@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")
- Spring环境中可用的属性的占位符。例如:
@EnabledIf("${smoke.tests.enabled}")
- 文本字面量。例如:
@EnabledIf("true")
然而,如果不是动态解析属性占位符的结果,文本字面量的实际应用价值为零,因为@EnabledIf("false")
等同于@Disabled
,而@EnabledIf("true")
在逻辑上是没有意义的。
你可以将@EnabledIf
作为元注解来创建自定义的组合注解。例如,你可以按如下方式创建一个自定义的@EnabledOnMac
注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Enabled on Mac OS"
)
public @interface EnabledOnMac {}
@EnabledOnMac
仅作为可能的示例。如果你确实有这个用例,请使用JUnit Jupiter内置的@EnabledOnOs(MAC)
支持。
自JUnit 5.7起,JUnit Jupiter也有一个名为@EnabledIf
的条件注解。因此,如果你希望使用Spring的@EnabledIf
支持,请确保你从正确的包中导入了注解类型。
@DisabledIf
@DisabledIf
用于表示,如果提供的表达式计算结果为true
,则标记的JUnit Jupiter测试类或测试方法将被禁用且不应运行。具体来说,如果表达式计算结果为Boolean.TRUE
或等于true
(忽略大小写)的字符串,则测试被禁用。当应用于类级别时,该类中的所有测试方法默认也会自动禁用。
表达式可以是以下任意一种:
- Spring Expression Language(SpEL)表达式。例如:
@DisabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")
- Spring环境中可用的属性的占位符。例如:
@DisabledIf("${smoke.tests.disabled}")
- 文本字面量。例如:
@DisabledIf("true")
然而,如果不是动态解析属性占位符的结果,文本字面量的实际应用价值为零,因为@DisabledIf("true")
等同于@Disabled
,而@DisabledIf("false")
在逻辑上是没有意义的。
你可以将@DisabledIf
作为元注解来创建自定义的组合注解。例如,你可以按如下方式创建一个自定义的@DisabledOnMac
注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Disabled on Mac OS"
)
public @interface DisabledOnMac {}
@DisabledOnMac
仅作为可能的示例。如果你确实有这个用例,请使用JUnit Jupiter内置的@DisabledOnOs(MAC)
支持。
自JUnit 5.7起,JUnit Jupiter也有一个名为@DisabledIf
的条件注解。因此,如果你希望使用Spring的@DisabledIf
支持,请确保你从正确的包中导入了注解类型。
测试的元注解支持
你可以将大多数与测试相关的注解作为元注解来创建自定义的组合注解,并减少测试套件中的配置重复。
你可以将以下每个注解与TestContext框架结合使用作为元注解。
@BootstrapWith
@ContextConfiguration
@ContextHierarchy
@ContextCustomizerFactories
@ActiveProfiles
@TestPropertySource
@DirtiesContext
@WebAppConfiguration
@TestExecutionListeners
@Transactional
@BeforeTransaction
@AfterTransaction
@Commit
@Rollback
@Sql
@SqlConfig
@SqlMergeMode
@SqlGroup
- @
Repeat
(仅支持JUnit 4) @Timed
(仅支持JUnit 4)@IfProfileValue
(仅支持JUnit 4)@ProfileValueSourceConfiguration
(仅支持JUnit 4)@SpringJUnitConfig
(仅支持JUnit Jupiter)@SpringJUnitWebConfig
(仅支持JUnit Jupiter)@TestConstructor
(仅支持JUnit Jupiter)@NestedTestConfiguration
(仅支持JUnit Jupiter)@EnabledIf
(仅支持JUnit Jupiter)@DisabledIf
(仅支持JUnit Jupiter)
考虑以下示例:
@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class OrderRepositoryTests { }
@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class UserRepositoryTests { }
如果我们发现自己在基于JUnit 4的测试套件中重复前一个配置,我们可以通过引入一个自定义的组合注解来减少重复,该注解集中了Spring的公共测试配置,如下所示:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }
然后我们可以使用自定义的@TransactionalDevTestConfig
注解来简化基于JUnit 4的单个测试类的配置,如下所示:
@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class OrderRepositoryTests { }
@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class UserRepositoryTests { }
如果我们编写使用JUnit Jupiter的测试,我们可以进一步减少代码重复,因为JUnit 5中的注解也可以作为元注解使用。考虑以下示例:
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
如果我们发现自己在基于JUnit Jupiter的测试套件中重复前一个配置,我们可以通过引入一个自定义的组合注解来减少重复,该注解集中了Spring和JUnit Jupiter的公共测试配置,如下所示:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }
然后我们可以使用自定义的@TransactionalDevTestConfig
注解来简化基于JUnit Jupiter的单个测试类的配置,如下所示:
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@TransactionalDevTestConfig
class UserRepositoryTests { }
由于JUnit Jupiter支持将@Test
、@RepeatedTest
、ParameterizedTest
等作为元注解使用,你也可以在测试方法级别创建自定义的组合注解。例如,如果我们希望创建一个组合注解,将JUnit Jupiter的@Test
和@Tag
注解与Spring的@Transactional
注解结合起来,我们可以创建一个@TransactionalIntegrationTest
注解,如下所示:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
public @interface TransactionalIntegrationTest { }
然后我们可以使用自定义的@TransactionalIntegrationTest
注解来简化基于JUnit Jupiter的单个测试方法的配置,如下所示:
@TransactionalIntegrationTest
void saveOrder() { }
@TransactionalIntegrationTest
void deleteOrder() { }