Spring: @BootstrapWith用于ApplicationContext

3

目前我使用@BootstrapWith注释与自定义类一起使用,它简单地设置了一些在测试中使用的系统属性。然而(据我所知),每次TestContextManager实例化测试和TestContext时都会设置这些属性:

@BootstrapWith是一个类级别的注解,用于配置Spring TestContext Framework的引导方式

spring.io

有没有办法在ApplicationContext启动之前仅设置一次属性?

编辑:

由于参数化测试需要@RunWith(Parameterized.class),因此我不能使用@RunWith(SpringJUnit4ClassRunner.class)。我使用SpringClassRule和SpringMethodRule代替

此外,我不仅运行参数化测试,还运行普通测试。因此,我不能简单地扩展Parameterized runner


你是指 System.getProperties() 吗? - Maciej Dobrowolski
在启动ApplicationContext之前,使用System.setProperty()。 - Anton
你需要全局设置属性还是每个测试套件应该有不同的属性? - Maciej Dobrowolski
@MaciejDobrowolski,它们应该是全局可用的,或者至少在当前的ApplicationContext中可用。我无法将它们绑定到套件上。 - Anton
4个回答

1
如果你只想在Spring应用程序上下文的引导过程中添加属性,你可以在Junit测试类顶部使用注释@TestPropertySource,像这样...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfig.class,SpringConfigForTests.class})
@TestPropertySource(properties = "runDate=20180110")
public class AcceptanceTests {
...

我使用这种技术来加载我的生产SpringConfig类(它加载属性文件),然后在SpringConfigForTests中覆盖一些特定于测试的bean(并潜在地加载测试特定的属性文件),然后添加另一个运行时属性名为runDate
我正在使用Spring 4.2.5.RELEASE,看起来这个注释自从4.1版本开始就已经被包含了。

1
我认为在ApplicationContext设置之前设置一些属性的最基本方法是编写自定义运行程序,例如:

public class MyRunner extends SpringJUnit4ClassRunner {

    public MyRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
        System.setProperty("sample.property", "hello world!");
    }

}

然后你可以使用它代替当前的运行器。

@RunWith(MyRunner.class)
@SpringBootTest
//....

如果您当前的Runner似乎被声明为final,您可以考虑使用聚合(但我没有测试过),而不是继承。

在这里,您可以找到一个示例Gist,在其中使用了该Runner并成功解析了属性。

更新

如果您不想使用自定义Runner(尽管您可以有几个Runner为每种情况设置属性 - 带参数,不带参数等)。 您可以使用@ClassRule,它适用于静态字段/方法 - 请参阅以下示例:

@ClassRule
public static ExternalResource setProperties() {
    return new ExternalResource() {
        @Override
        public Statement apply(Statement base, Description description) {
            System.setProperty("sample.property", "hello world!");
            return super.apply(base, description);
        }
    };
}

这个静态方法应该放在你的测试类中。


可能我在问题中应该提到:由于参数化测试需要@RunWIth(Parameterized.class),我无法使用@RunWith(SpringJUnit4ClassRunner.class)。我改用SpringClassRule和SpringMethodRule。 - Anton
@Anton 为什么不扩展 Parameterized runner? - Maciej Dobrowolski
在这种情况下,我将无法为普通的非参数化测试设置属性。 - Anton
谢谢。我在下面发布了额外的答案,但出于感激您花费的时间,我将接受您的答案。 - Anton

0

如果您最终将程序参数作为ApplicationArguments使用,则可以在测试上下文中提供一个ApplicationArguments。它将与通过@SpringBootTest提供的空参数相冲突,但您可以通过将其注释为@Primary来强制使用。

@Component
public class ArgReadingBean {
  public ArgReadingBean(ApplicationArguments arguments) {
    // ...
  }
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestConfig.class, ArgDependentBean.class })
public class AppArgsTest {
  @Resource
  private ArgReadingBean bean;

  public static class TestConfig {
    @Bean
    @Primary
    ApplicationArguments myArguments() {
      return new DefaultApplicationArguments("-help");
    }
  }

  @Test
  public void testArgs() {
    assertThat(bean).isNotNull(); // or whatever
  }
}

0

我发现这可以通过扩展AnnotationConfigContextLoader(或任何其他ContextLoader)并覆盖prepareContext()方法来实现:

@Override
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
    // set properties here
    super.prepareContext(context, mergedConfig);
}

自定义的加载器应该在测试实例的@ContextConfiguration注释中指定


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