如何在单元测试中设置不同的类路径以使用 Spring 加载资源
How to set different classpath in an unit test to load resource with Spring
我想用 JUnit 和 Spring 创建 2 个测试用例,它们都需要相同的 classpath 资源 batch-configuration.properties但此文件的内容因测试而异。
实际上在我的 maven 项目中,我创建了这些文件树:
- src/test/resources/test1/batch-configuration.properties
- src/test/resources/test2/batch-configuration.properties
但是我如何根据我的测试用例定义我的根 class 路径(文件使用 classpath:batch-configuration.properties
在 ExtractionBatchConfiguration
中加载)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class }, loader = AnnotationConfigContextLoader.class)
@PropertySource("classpath:test1/batch-configuration.properties") // does not override ExtractionBatchConfiguration declaration
public class ExtractBatchTestCase {
private static ConfigurableApplicationContext context;
private JobLauncherTestUtils jobLauncherTestUtils;
@BeforeClass
public static void beforeClass() {
context = SpringApplication.run(ExtractionBatchConfiguration.class);
}
@Before
public void setup() throws Exception {
jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJobLauncher(context.getBean(JobLauncher.class));
jobLauncherTestUtils.setJobRepository(context.getBean(JobRepository.class));
}
@Test
public void testGeneratedFiles() throws Exception {
jobLauncherTestUtils.setJob(context.getBean("extractJob1", Job.class));
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertNotNull(jobExecution);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
// ... other assert
}
}
配置:
@Configuration
@EnableAutoConfiguration
@PropertySources({
@PropertySource("batch-default-configuration.properties"),
@PropertySource("batch-configuration.properties")
})
public class ExtractionBatchConfiguration { /* ... */ }
我正在使用 Spring 4.0.9(我不能使用 4.1.x)和 JUnit 4.11
编辑:
在使用 hzpz 建议的自定义 ApplicationContextInitializer 覆盖我的解决了一些问题的属性位置(application.properties + batch-configuration.properties)之后,我遇到了 @ConfigurationProperties 的另一个问题:
@ConfigurationProperties(prefix = "spring.ldap.contextsource"/*, locations = "application.properties"*/)
public class LdapSourceProperties {
String url;
String userDn;
String password;
/* getters, setters */
}
和配置:
@Configuration
@EnableConfigurationProperties(LdapSourceProperties.class)
public class LdapConfiguration {
@Bean
public ContextSource contextSource(LdapSourceProperties properties) {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(properties.getUrl());
contextSource.setUserDn(properties.getUserDn());
contextSource.setPassword(properties.getPassword());
return contextSource;
}
}
创建 ContextSource 时,所有 LdapSourceProperties 的字段均为空,但如果我取消注释 locations = "application.properties"
,它仅在 application.properties 位于根 class 路径中时才有效。 @ConfigurationProperties 使用的默认环境似乎不包含需要的属性...
备选方案:
最后,我将所有属性放入 application-<profile>.properties
文件(并删除 @PropertySource 定义)。我现在可以使用 application-test1.properties
和 application-test2.properties
。在我的测试 class 中,我可以设置 @ActiveProfiles("test1")
来激活配置文件并加载相关属性。
首先,您需要了解 Spring 的 JUnit 测试是如何工作的。 SpringJUnit4ClassRunner
的目的是为您创建 ApplicationContext
(使用 @ContextConfiguration
)。您不需要自己创建上下文。
如果上下文设置正确,您可以使用 @Autowired
获取测试中所需的依赖项。 ExtractBatchTestCase
应该看起来像这样:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class })
public class ExtractBatchTestCase {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private JobRepository jobRepository;
@Autowired
@Qualifier("extractJob1")
private Job job;
private JobLauncherTestUtils jobLauncherTestUtils;
@Before
public void setup() throws Exception {
jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJobLauncher(jobLauncher);
jobLauncherTestUtils.setJobRepository(jobRepository);
}
@Test
public void testGeneratedFiles() throws Exception {
jobLauncherTestUtils.setJob(job);
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertNotNull(jobExecution);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
// ... other assert
}
}
其次,@ProperySource
的 Javadoc 声明:
In cases where a given property key exists in more than one .properties file, the last @PropertySource
annotation processed will 'win' and override. [...]
In certain situations, it may not be possible or practical to tightly control property source ordering when using @ProperySource
annotations. For example, if the @Configuration
classes [...] were registered via component-scanning, the ordering is difficult to predict. In such cases - and if overriding is important - it is recommended that the user fall back to using the programmatic PropertySource API.
为您的测试创建一个 ApplicationContextInitializer
以添加一些具有最高搜索优先级的测试属性,这些属性将始终 'win':
public class MockApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
MockPropertySource mockEnvVars = new MockPropertySource().withProperty("foo", "bar");
propertySources.addFirst(mockEnvVars);
}
}
使用@ContextConfiguration
声明它:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class },
initializers = MockApplicationContextInitializer.class)
public class ExtractBatchTestCase {
// ...
}
我想用 JUnit 和 Spring 创建 2 个测试用例,它们都需要相同的 classpath 资源 batch-configuration.properties但此文件的内容因测试而异。
实际上在我的 maven 项目中,我创建了这些文件树:
- src/test/resources/test1/batch-configuration.properties
- src/test/resources/test2/batch-configuration.properties
但是我如何根据我的测试用例定义我的根 class 路径(文件使用 classpath:batch-configuration.properties
在 ExtractionBatchConfiguration
中加载)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class }, loader = AnnotationConfigContextLoader.class)
@PropertySource("classpath:test1/batch-configuration.properties") // does not override ExtractionBatchConfiguration declaration
public class ExtractBatchTestCase {
private static ConfigurableApplicationContext context;
private JobLauncherTestUtils jobLauncherTestUtils;
@BeforeClass
public static void beforeClass() {
context = SpringApplication.run(ExtractionBatchConfiguration.class);
}
@Before
public void setup() throws Exception {
jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJobLauncher(context.getBean(JobLauncher.class));
jobLauncherTestUtils.setJobRepository(context.getBean(JobRepository.class));
}
@Test
public void testGeneratedFiles() throws Exception {
jobLauncherTestUtils.setJob(context.getBean("extractJob1", Job.class));
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertNotNull(jobExecution);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
// ... other assert
}
}
配置:
@Configuration
@EnableAutoConfiguration
@PropertySources({
@PropertySource("batch-default-configuration.properties"),
@PropertySource("batch-configuration.properties")
})
public class ExtractionBatchConfiguration { /* ... */ }
我正在使用 Spring 4.0.9(我不能使用 4.1.x)和 JUnit 4.11
编辑:
在使用 hzpz 建议的自定义 ApplicationContextInitializer 覆盖我的解决了一些问题的属性位置(application.properties + batch-configuration.properties)之后,我遇到了 @ConfigurationProperties 的另一个问题:
@ConfigurationProperties(prefix = "spring.ldap.contextsource"/*, locations = "application.properties"*/)
public class LdapSourceProperties {
String url;
String userDn;
String password;
/* getters, setters */
}
和配置:
@Configuration
@EnableConfigurationProperties(LdapSourceProperties.class)
public class LdapConfiguration {
@Bean
public ContextSource contextSource(LdapSourceProperties properties) {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(properties.getUrl());
contextSource.setUserDn(properties.getUserDn());
contextSource.setPassword(properties.getPassword());
return contextSource;
}
}
创建 ContextSource 时,所有 LdapSourceProperties 的字段均为空,但如果我取消注释 locations = "application.properties"
,它仅在 application.properties 位于根 class 路径中时才有效。 @ConfigurationProperties 使用的默认环境似乎不包含需要的属性...
备选方案:
最后,我将所有属性放入 application-<profile>.properties
文件(并删除 @PropertySource 定义)。我现在可以使用 application-test1.properties
和 application-test2.properties
。在我的测试 class 中,我可以设置 @ActiveProfiles("test1")
来激活配置文件并加载相关属性。
首先,您需要了解 Spring 的 JUnit 测试是如何工作的。 SpringJUnit4ClassRunner
的目的是为您创建 ApplicationContext
(使用 @ContextConfiguration
)。您不需要自己创建上下文。
如果上下文设置正确,您可以使用 @Autowired
获取测试中所需的依赖项。 ExtractBatchTestCase
应该看起来像这样:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class })
public class ExtractBatchTestCase {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private JobRepository jobRepository;
@Autowired
@Qualifier("extractJob1")
private Job job;
private JobLauncherTestUtils jobLauncherTestUtils;
@Before
public void setup() throws Exception {
jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJobLauncher(jobLauncher);
jobLauncherTestUtils.setJobRepository(jobRepository);
}
@Test
public void testGeneratedFiles() throws Exception {
jobLauncherTestUtils.setJob(job);
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertNotNull(jobExecution);
Assert.assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
// ... other assert
}
}
其次,@ProperySource
的 Javadoc 声明:
In cases where a given property key exists in more than one .properties file, the last
@PropertySource
annotation processed will 'win' and override. [...]In certain situations, it may not be possible or practical to tightly control property source ordering when using
@ProperySource
annotations. For example, if the@Configuration
classes [...] were registered via component-scanning, the ordering is difficult to predict. In such cases - and if overriding is important - it is recommended that the user fall back to using the programmatic PropertySource API.
为您的测试创建一个 ApplicationContextInitializer
以添加一些具有最高搜索优先级的测试属性,这些属性将始终 'win':
public class MockApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
MockPropertySource mockEnvVars = new MockPropertySource().withProperty("foo", "bar");
propertySources.addFirst(mockEnvVars);
}
}
使用@ContextConfiguration
声明它:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ExtractionBatchConfiguration.class },
initializers = MockApplicationContextInitializer.class)
public class ExtractBatchTestCase {
// ...
}