Context Configuration with Test Property Sources
Spring Framework 一流地支持具有属性源层次结构的环境概念,并且您可以配置包含特定于测试的属性源的集成测试。与 @Configuration
类中使用的 @PropertySource
注释相反,你可以在测试类中声明 @TestPropertySource
注释,以声明测试属性文件或内联属性的资源位置。这些测试属性源被添加到为带注释的集成测试加载的 ApplicationContext
的 Environment
中的 PropertySources
集中。
The Spring Framework has first-class support for the notion of an environment with a
hierarchy of property sources, and you can configure integration tests with test-specific
property sources. In contrast to the @PropertySource
annotation used on
@Configuration
classes, you can declare the @TestPropertySource
annotation on a test
class to declare resource locations for test properties files or inlined properties.
These test property sources are added to the set of PropertySources
in the
Environment
for the ApplicationContext
loaded for the annotated integration test.
你可以在任何 You can use
Implementations of |
Declaring Test Property Sources
你可以使用 @TestPropertySource
的 locations
或 value
属性配置测试属性文件。
You can configure test properties files by using the locations
or value
attribute of
@TestPropertySource
.
默认情况下,支持传统的和基于 XML 的 java.util.Properties
文件格式,例如 "classpath:/com/example/test.properties"
或 "file:///path/to/file.xml"
。从 Spring Framework 6.1 开始,你可以通过 @TestPropertySource
中的 factory
属性配置自定义 PropertySourceFactory
,以支持不同的文件格式,例如 JSON、YAML 等。
By default, both traditional and XML-based java.util.Properties
file formats are
supported — for example, "classpath:/com/example/test.properties"
or
"file:///path/to/file.xml"
. As of Spring Framework 6.1, you can configure a custom
PropertySourceFactory
via the factory
attribute in @TestPropertySource
in order to
support a different file format such as JSON, YAML, etc.
每条路径都被解释为 Spring Resource
。普通路径(例如 "test.properties"
)被视为相对于定义测试类的包的类路径资源。以斜杠开头的路径被视为绝对类路径资源(例如:"/org/example/test.xml"
)。引用 URL 的路径(例如以 classpath:
, file:
, 或 http:
为前缀的路径)使用指定的资源协议加载。
Each path is interpreted as a Spring Resource
. A plain path (for example,
"test.properties"
) is treated as a classpath resource that is relative to the package
in which the test class is defined. A path starting with a slash is treated as an
absolute classpath resource (for example: "/org/example/test.xml"
). A path that
references a URL (for example, a path prefixed with classpath:
, file:
, or http:
) is
loaded by using the specified resource protocol.
路径中的属性占位符(例如 ${…}
) 将针对 Environment
进行解析。
Property placeholders in paths (such as ${…}
) will be resolved against the Environment
.
从 Spring Framework 6.1 开始,也支持资源位置模式 — 例如,"classpath*:/config/*.properties"
。
As of Spring Framework 6.1, resource location patterns are also supported — for
example, "classpath*:/config/*.properties"
.
以下示例使用测试属性文件:
The following example uses a test properties file:
- Java
-
@ContextConfiguration @TestPropertySource("/test.properties") (1) class MyIntegrationTests { // class body... }
1 | Specifying a properties file with an absolute path.
|
2 | Specifying a properties file with an absolute path. |
你可以使用 @TestPropertySource
的 properties
属性以键值对的形式配置内联属性,如下一示例所示。所有键值对作为具有最高优先级的单个测试 PropertySource
添加到包含的 Environment
中。
You can configure inlined properties in the form of key-value pairs by using the
properties
attribute of @TestPropertySource
, as shown in the next example. All
key-value pairs are added to the enclosing Environment
as a single test
PropertySource
with the highest precedence.
键值对支持的语法与 Java 属性文件中为条目定义的语法相同:
The supported syntax for key-value pairs is the same as the syntax defined for entries in a Java properties file:
-
key=value
-
key:value
-
key value
虽然可以使用上面任何一种语法变体和在键和值之间的任何空格来定义属性,但建议您在测试套件中使用一种语法变体和一致的间距——例如,始终考虑使用 Although properties can be defined using any of the above syntax variants and any number
of spaces between the key and the value, it is recommended that you use one syntax
variant and consistent spacing within your test suite — for example, consider always
using 原因在于您提供的 exact 字符串将用于确定情境缓存的键。因此,要从情境缓存中受益,您必须确保一致地定义内联属性。 The reason is that the exact strings you provide will be used to determine the key for the context cache. Consequently, to benefit from the context cache you must ensure that you define inlined properties consistently. |
以下示例设置了两个内联属性:
The following example sets two inlined properties:
- Java
-
@ContextConfiguration @TestPropertySource(properties = {"timezone = GMT", "port = 4242"}) (1) class MyIntegrationTests { // class body... }
1 | Setting two properties via an array of strings.
|
2 | Setting two properties via an array of strings. |
从 Spring 框架 6.1 开始,您可以使用 文本块 在单个 String
中定义多个内联属性。以下示例使用文本块设置了两个内联属性:
As of Spring Framework 6.1, you can use text blocks to define multiple inlined
properties in a single String
. The following example sets two inlined properties using
a text block:
- Java
-
@ContextConfiguration @TestPropertySource(properties = """ timezone = GMT port = 4242 """) (1) class MyIntegrationTests { // class body... }
1 | Setting two properties via a text block.
|
2 | Setting two properties via a text block. |
从 Spring 框架 5.2 开始, As of Spring Framework 5.2, 此外,您可以在测试类上声明多个组合注释,每个注释都使用 In addition, you may declare multiple composed annotations on a test class that are each
meta-annotated with 直接呈现 Directly present |
Default Properties File Detection
如果 @TestPropertySource
被声明为一个空注释(即没有 locations
或 properties
属性的显式值),则会尝试检测声明该注释的类相对于默认属性文件的检测。例如,如果带注释的测试类是 com.example.MyTest
,则相应的默认属性文件是 classpath:com/example/MyTest.properties
。如果无法检测到默认值,则会抛出 IllegalStateException
。
If @TestPropertySource
is declared as an empty annotation (that is, without explicit
values for the locations
or properties
attributes), an attempt is made to detect a
default properties file relative to the class that declared the annotation. For example,
if the annotated test class is com.example.MyTest
, the corresponding default properties
file is classpath:com/example/MyTest.properties
. If the default cannot be detected, an
IllegalStateException
is thrown.
Precedence
测试属性的优先级高于操作系统环境、Java 系统属性或应用程序使用 @PropertySource
声明式或以编程的方式(通过 @TestPropertySource
)添加的属性源中定义的那些属性。因此,测试属性可以用来选择性地覆盖从系统和应用程序属性源加载的属性。此外,内联属性的优先级高于从资源位置加载的属性。但是请注意,通过 @DynamicPropertySource
注册的属性的优先级高于通过 @TestPropertySource
加载的那些属性。
Test properties have higher precedence than those defined in the operating system’s
environment, Java system properties, or property sources added by the application
declaratively by using @PropertySource
or programmatically. Thus, test properties can
be used to selectively override properties loaded from system and application property
sources. Furthermore, inlined properties have higher precedence than properties loaded
from resource locations. Note, however, that properties registered via
@DynamicPropertySource
have
higher precedence than those loaded via @TestPropertySource
.
在下一个示例中,timezone
和 port
属性以及在“/test.properties
”中定义的任何属性都将覆盖在系统和应用程序属性源中定义的名称相同的任何属性。此外,如果 "/test.properties"
文件为 timezone
和 port
属性定义了条目,则会被使用 properties
属性声明的内联属性覆盖。以下示例显示了如何在文件和内联中指定属性:
In the next example, the timezone
and port
properties and any properties defined in
"/test.properties"
override any properties of the same name that are defined in system
and application property sources. Furthermore, if the "/test.properties"
file defines
entries for the timezone
and port
properties those are overridden by the inlined
properties declared by using the properties
attribute. The following example shows how
to specify properties both in a file and inline:
-
Java
-
Kotlin
@ContextConfiguration
@TestPropertySource(
locations = "/test.properties",
properties = {"timezone = GMT", "port = 4242"}
)
class MyIntegrationTests {
// class body...
}
@ContextConfiguration
@TestPropertySource("/test.properties",
properties = ["timezone = GMT", "port = 4242"]
)
class MyIntegrationTests {
// class body...
}
Inheriting and Overriding Test Property Sources
@TestPropertySource
支持布尔型 inheritLocations
和 inheritProperties
属性,它们表示是否应继承超类声明的属性文件和内联属性的资源位置。这两个标志的默认值为 true
。这意味着测试类会继承超类声明的位置和内联属性。具体来说,测试类的位置和内联属性将附加到超类声明的位置和内联属性后面。因此,子类可以选择扩展位置和内联属性。请注意,稍后出现的属性会覆盖(即覆盖)先前的名称相同的属性。此外,上述优先级规则也适用于继承的测试属性源。
@TestPropertySource
supports boolean inheritLocations
and inheritProperties
attributes that denote whether resource locations for properties files and inlined
properties declared by superclasses should be inherited. The default value for both flags
is true
. This means that a test class inherits the locations and inlined properties
declared by any superclasses. Specifically, the locations and inlined properties for a
test class are appended to the locations and inlined properties declared by superclasses.
Thus, subclasses have the option of extending the locations and inlined properties. Note
that properties that appear later shadow (that is, override) properties of the same name
that appear earlier. In addition, the aforementioned precedence rules apply for inherited
test property sources as well.
如果 @TestPropertySource
中的 inheritLocations
或 inheritProperties
属性设置为 false
,则测试类的位置或内联属性将覆盖并有效地替换超类定义的配置。
If the inheritLocations
or inheritProperties
attribute in @TestPropertySource
is
set to false
, the locations or inlined properties, respectively, for the test class
shadow and effectively replace the configuration defined by superclasses.
从 Spring Framework 5.3 开始,还可以从封闭类继承测试配置。请参阅 |
As of Spring Framework 5.3, test configuration may also be inherited from enclosing
classes. See |
在下一个示例中,BaseTest
的 ApplicationContext
只能使用 base.properties
文件作为测试属性源进行加载。相反,ExtendedTest
的 ApplicationContext
会使用 base.properties
和 extended.properties
文件作为测试属性源位置进行加载。以下示例显示了如何使用 properties
文件在子类及其超类中定义属性:
In the next example, the ApplicationContext
for BaseTest
is loaded by using only the
base.properties
file as a test property source. In contrast, the ApplicationContext
for ExtendedTest
is loaded by using the base.properties
and extended.properties
files as test property source locations. The following example shows how to define
properties in both a subclass and its superclass by using properties
files:
-
Java
-
Kotlin
@TestPropertySource("base.properties")
@ContextConfiguration
class BaseTest {
// ...
}
@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest extends BaseTest {
// ...
}
@TestPropertySource("base.properties")
@ContextConfiguration
open class BaseTest {
// ...
}
@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest : BaseTest() {
// ...
}
在下一个示例中,BaseTest
的 ApplicationContext
只能使用内联 key1
属性进行加载。相反,ExtendedTest
的 ApplicationContext
会使用内联 key1
和 key2
属性进行加载。以下示例显示了如何使用内联属性在子类及其超类中定义属性:
In the next example, the ApplicationContext
for BaseTest
is loaded by using only the
inlined key1
property. In contrast, the ApplicationContext
for ExtendedTest
is
loaded by using the inlined key1
and key2
properties. The following example shows how
to define properties in both a subclass and its superclass by using inline properties:
-
Java
-
Kotlin
@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
class BaseTest {
// ...
}
@TestPropertySource(properties = "key2 = value2")
@ContextConfiguration
class ExtendedTest extends BaseTest {
// ...
}
@TestPropertySource(properties = ["key1 = value1"])
@ContextConfiguration
open class BaseTest {
// ...
}
@TestPropertySource(properties = ["key2 = value2"])
@ContextConfiguration
class ExtendedTest : BaseTest() {
// ...
}