java - 如何在单元测试中设置不同的类路径以使用 Spring 加载资源

标签 java spring unit-testing spring-boot spring-batch

我想用 JUnit 和 Spring 创建 2 个测试用例,它们都需要相同的类路径资源 batch-configuration.properties 但此文件的内容因测试而异。

实际上在我的 maven 项目中,我创建了这些文件树:

  • src/test/resources/test1/batch-configuration.properties
  • src/test/resources/test2/batch-configuration.properties

但是我如何根据我的测试用例定义我的根类路径(文件加载到 ExtractionBatchConfiguration 使用 classpath:batch-configuration.properties )

@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 位于根类路径中时才有效。 @ConfigurationProperties 使用的默认环境似乎不包含需要的属性...

替代解决方案:

最后我把我所有的属性都放入application-<profile>.properties文件(并删除@PropertySource 定义)。我现在可以使用 application-test1.propertiesapplication-test2.properties .在我的测试课上,我可以设置 @ActiveProfiles("test1")激活配置文件并加载相关属性。

最佳答案

首先,您需要了解 JUnit 测试与 Spring 的工作原理。 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
    }

}

二、Javadoc对于 @ProperySource 状态:

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,以添加一些具有最高搜索优先级且始终“获胜”的测试属性:

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 {
    // ...
}

关于java - 如何在单元测试中设置不同的类路径以使用 Spring 加载资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32187488/

相关文章:

python - 进行单元测试时未定义名称 'self'?

angular - 失败 : Template parse errors: Angular 2

java - 从字符串创建对象

spring - 如何在 Mockito 中注入(inject) Prototype bean

spring - 用 Thymeleaf 扩展视野

spring - 是否有使用其他Spring版本的简单方法?

sql - 如何使用sql查询将数据库的子集提取到dbunit文件中?

java - AppIdentityCredential 和 AppEngineDataStoreFactory

java - 鼠标 clickAndHold() 在使用 Selenium Webdriver 的 Firefox 上无法正常工作

java - Google GCM XMPP 代码示例