如何使用 @IfProfileValue 来测试 Profile 是否处于活动状态?

10

让人困惑的是,@IfProfileValue@Profile@ActiveProfiles 没有任何关系。 @Profile 用于测试配置文件是否已激活,@ActiveProfiles 则用于设置它们的激活状态,@IfProfileValue 允许您在 Spring Environment 中检查一些东西。什么?我会弃用它们所有的,并添加新的 @IfEnvironment@IfProfile@ActivateProfiles

抛开评论,如何使用 @IfProfileValue 检测我是否已激活了某个配置文件?目前我没有在这个项目中使用 Spring Boot。答案应该包含代码,我们将假设如果配置文件被激活为 @ActiveProfiles( "test" ) ,则我希望测试运行。

我尝试使用 @IfProfileValue(name = "activeProfiles", value = "test"),但似乎测试被跳过了,也就是说它没有匹配成功。我猜测问题可能与 ActiveProfiles 是一个 Collection 有关。

4个回答

26
如此混淆的是,@IfProfileValue@Profile@ActiveProfiles没有任何关系。这是正确的,并且我在这里详细解释了这一点: https://dev59.com/j2Ag5IYBdhLWcg3wbqd4#23627479 我假设你已经看到了它,因为你昨天评论了我的答案。 @IfProfileValue@Profile@ActiveProfiles无关的原因是由于框架的演变。有关详细信息,请参见下面的内容。 @Profile测试是否激活配置文件,@ActiveProfiles将它们设置为活动状态,@IfProfileValue允许您在Spring Environment中检查内容。这些陈述不完全正确,特别是最后一部分。

@Profile被用于有选择地启用一个组件(例如@Service等)、@Configuration类或@Bean方法,如果Spring的EnvironmentApplicationContext激活了其中一个命名的bean定义配置文件。该注释与测试无直接关系:@Profile不应在测试类上使用。

@ActiveProfiles用于指定哪些bean定义配置文件(例如通过@Profile声明的那些)在加载集成测试的ApplicationContext时应处于活动状态。

@IfProfileValue不允许您检查Spring的Environment中的事情。我不确定您为什么会这样假设,因为Spring Framework的文档中没有提到。正如我在前面提到的帖子中所述:

请注意,@IfProfileValue是在Spring Framework 2.0中引入的,远在bean定义配置文件的概念之前,而@ActiveProfiles是在Spring Framework 3.1中首次引入的。

在上述主题中,我还指出了以下内容:

考虑到@IfProfileValue的语义,术语“配置文件”可能会产生误导。关键是要考虑“测试组”(例如TestNG中的测试组),而不是“配置文件”。请参见JavaDoc for @IfProfileValue中的示例。

我如何使用@IfProfileValue来检测是否已激活配置文件?

这取决于情况,我假设你说“配置文件”时是指bean定义配置文件

如果您正在使用@ActiveProfiles来设置测试的bean定义配置文件,则不能使用@IfProfileValue来确定是否激活了bean定义配置文件,因为通过@ActiveProfiles配置的bean定义配置文件直接设置在测试的ApplicationContext中,而不是作为Java系统属性。

然而,如果您仅通过 spring.profiles.active 系统属性设置 bean 定义配置文件,则可以使用 @IfProfileValue 来确定是否激活了一个 bean 定义配置文件,因为 @IfProfileValue 实际上是使用系统属性工作的。例如,您可以使用以下内容:
@IfProfileValue(name = "spring.profiles.active", value = "test")

我试过@IfProfileValue(name = "activeProfiles", value = "test"),但似乎测试被跳过了,这意味着它不匹配。
那行不通,因为activeProfiles是错误的属性名称。正确的系统属性名称是spring.profiles.active。有关详细信息,请参见AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME

@IfProfileValue@ActiveProfiles 不兼容是 Spring 团队已知的问题。如果您想了解更多详情并参与讨论,请参考以下 JIRA 问题。

希望这能为您澄清情况!Sam(Spring TestContext Framework的作者)

我认为我从jira/SO线程中得到了“环境”概念...我也可能假设它正在使用属性源合并器,据我所知,这将允许访问环境。我的错误。我知道命名差异有历史原因,这就是为什么我会在v5中弃用它们并赋予它们新名称的原因。我发现所有注释都有一些不明显的用途,这些用途无法通过查看使用它们的代码来确定。 - xenoterracide
2
一个反馈是,如果您有多个活动配置文件,则检查 spring.profiles.active 是否与特定配置文件匹配将失败,因为存在多个逗号分隔的配置文件名称。 - Shawn Clark
你能指出为什么在测试类上不应该使用@Profile吗?请参见https://stackoverflow.com/q/53313489/4106030 - badera

6

Sam做得很好。(此外,这个问题已经在几年前被接受并回答了)

还有一件事需要补充的是,如果你想将系统属性传递给你的测试,如果你使用像Gradle这样的构建工具,让它们传播到JVM可能需要额外的步骤。

//build.gradle
tasks.withType(Test) {
    systemProperties System.properties
}

然后在您的集成测试中按照惯例进行业务操作

//MyIntegrationTest.class
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("integration")
@IfProfileValue(name = "run.integration.tests", value = "true")
public class MyIntegrationTest {
    @Test
    public void myTest(){ ... }
}

最后,您可以使用指定的属性从终端执行测试。
$> ./gradlew clean test -Drun.integration.tests=true

相比手动获取系统属性并检查assumeTrue/False,我最喜欢@IfProfileValue的一点是没有加载Spring上下文(或者您可能有的flyway/其他迁移),从而使单元测试更快。


话虽如此,我意识到我在这里加入了“集成测试”,而这并没有在 OP 中提到。 - mcnichol
嗯,我们把它用于与上游 API 提供商的集成测试,以避免每次测试运行时滥用他们的 API。 - xenoterracide

2
很遗憾,根据我的经验,@IfProfileValue对测试依赖性很高。最初的回答。
@Test
@IfProfileValue(name="spring.profiles.active", values={"test"})

只有在将spring.profiles.active设置为JVM属性时才能起作用,例如: -Dspring.profiles.active="test"。最初的回答。
@IfProfileValue just ignores spring.profiles.active from application.properties/yml.

确认。另一个重要节点:在测试属性name="spring.profiles.active"时,必须使用@IfProfileValue'OR'语义。因此,@IfProfileValue(name="spring.profiles.active", values={"test"})有效,但@IfProfileValue(name="spring.profiles.active", value="test")无效。 - brianNotBob
对于junit5,可能需要使用以下注释:https://dev59.com/NFQJ5IYBdhLWcg3wf2Ed#53718280 - Kyle Dunn

0

使用junit5时,可以根据活动配置文件有条件地启用测试:

@EnabledIf(expression =
   "#{environment.acceptsProfiles(T(org.springframework.core.env.Profiles).of('someprofile'))}",
   loadContext = true)
class MyTest {
   ...
}

这个检查是否someprofile是活动的,与检查spring.profiles.active属性不同,即使有多个配置文件启用也可以工作。这将检查someprofile是否在当前活动配置文件中。

为了使其更易读,可以使用Spring元注释。首先定义注释。

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@EnabledIf(expression =
  "#{environment.acceptsProfiles(T(org.springframework.core.env.Profiles).of('someprofile'))}",
  loadContext = true)
public @interface EnabledIfSomeProfile {
}

然后在测试类中使用它:

@EnableIfSomeProfile
class MyTest {
 ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接