英文:
Using actual properties file from src/main/resources with Spring @PropertySource in JUnit test
问题
我正试图使用 H2 数据库而不是实际数据库来对 DAO 类进行单元测试。在尝试让我的测试用例使用位于 src/main/resources/properties/
文件夹中的属性文件时,我遇到了一个问题:
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@PropertySource("classpath:properties/common.properties")
@ContextConfiguration(locations = { "/spring/common-context.xml" })
public class ConfigDAOImplTest {
@Autowired
private ConfigDAOImpl configDAO;
@Spy
private ContextParamDAO contextParamDAO = new ContextParamDAOImpl();
private static final String SCHEMA_CONFIG = "classpath:data/CONFIG_SCHEMA.sql";
private static final String DATA_CONFIG = "classpath:data/CONFIG_DATA.sql";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
DataSource dataSource = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript(SCHEMA_CONFIG)
.addScript(DATA_CONFIG)
.build();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//override the jdbcTemplate for the test case
configDAO.setJdbcTemplate(jdbcTemplate);
configDAO.setContextParamDAO(contextParamDAO);
}
//.. more code
}
common-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="commonAppProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>file:${conf_folder_path}/common.properties</value>
</list>
</property>
</bean>
<bean id="configDAO"
class="com.myproject.common.dataaccess.impl.ConfigDAOImpl" scope="step">
<property name="jdbcTemplate" ref="jdbcTemplate" />
<property name="corePoolSize" value="${threadpool.size}"/>
</bean>
</beans>
当我运行测试类时,我得到以下异常:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'corePoolSize'; nested exception is java.lang.NumberFormatException: For input string: "${threadpool.size}"
测试用例无法找到所需的属性的一个原因是:
PropertyPlaceholderConfigurer
bean 引用了{conf_folder_path}/common.properties
,这是 Maven 构建系统将src/main/resources/properties/common.properties
复制到的路径。- 然而,在 Eclipse 中,没有
{conf_folder_path}
,因为这是由 Maven 创建的。
问题: 假设上述原因是问题的根本原因,我该如何使测试用例找到属性,考虑到 Spring 上下文中引用的路径与源代码中的路径不同。
英文:
I am trying to unit test a DAO class by using a H2 database instead of an actual database. I am facing an issue while trying to make my test case use a properties file that is present in the src/main/resources/properties/
folder :
Test class
@RunWith(SpringJUnit4ClassRunner.class)
@PropertySource("classpath:properties/common.properties")
@ContextConfiguration(locations = { "/spring/common-context.xml" })
public class ConfigDAOImplTest {
@Autowired
private ConfigDAOImpl configDAO;
@Spy
private ContextParamDAO contextParamDAO = new ContextParamDAOImpl();
private static final String SCHEMA_CONFIG = "classpath:data/CONFIG_SCHEMA.sql";
private static final String DATA_CONFIG = "classpath:data/CONFIG_DATA.sql";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
DataSource dataSource = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript(SCHEMA_CONFIG)
.addScript(DATA_CONFIG)
.build();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//override the jdbcTemplate for the test case
configDAO.setJdbcTemplate(jdbcTemplate);
configDAO.setContextParamDAO(contextParamDAO);
}
//.. more coode
}
common-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="commonAppProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>file:${conf_folder_path}/common.properties</value>
</list>
</property>
</bean>
<bean id="configDAO"
class="com.myproject.common.dataaccess.impl.ConfigDAOImpl" scope="step">
<property name="jdbcTemplate" ref="jdbcTemplate" />
<property name="corePoolSize" value="${threadpool.size}"/>
</bean>
</beans>
When I run the test class, I get the following exception :
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'corePoolSize'; nested exception is java.lang.NumberFormatException: For input string: "${threadpool.size}"
One reason for the test case not being able to find the required property is because :
- The
PropertyPlaceholderConfigurer
bean refers to
{conf_folder_path}/common.properties
which is the path where
src/main/resources/properties/common.properties
gets copied to by Maven build system. - However , in Eclipse, there is no
{conf_folder_path}
as this is created by Maven.
Question : Assumnig that the above reason is the root cause of the issue, how do I make the test case find the properties considering the path refereed to in the Spring context is different from that in the source code.
答案1
得分: 1
可以创建类似以下内容的代码:
@Configuration
public class TestConfiguration {
private static final Logger log = LoggerFactory.getLogger(TestConfiguration.class);
@Autowired
private Environment env;
/**
* 此 Bean 在使用来自 src/main/resources/properties 目录下的属性文件时是必需的
* @param env 环境变量
* @return 带有正确属性文件的属性源配置器
*/
@Bean
public PropertySourcesPlaceholderConfigurer placeholderConfigurerDev(ConfigurableEnvironment env) {
final String fileName = "common.properties";
Path resourceDirectory = Paths.get("src", "main", "resources", "properties");
String absolutePath = resourceDirectory.toFile().getAbsolutePath();
final File file = new File(absolutePath.concat("/").concat(fileName));
if (file.exists()) {
try {
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(new PropertiesPropertySource(fileName, PropertiesLoaderUtils.loadAllProperties(file.getName())));
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
throw new RuntimeException(ex.getMessage(), ex);
}
}
this.env = env;
return new PropertySourcesPlaceholderConfigurer();
}
}
英文:
You can create something like this:
@Configuration
public class TestConfiguration {
private static final Logger log = LoggerFactory.getLogger(TestConfiguration.class);
@Autowired
private Environment env;
/**
* This bean is necessary in order to use property file from src/main/resources/properties
* @param env environment
* @return property source configurator with correct property file
*/
@Bean
public PropertySourcesPlaceholderConfigurer placeholderConfigurerDev(ConfigurableEnvironment env) {
final String fileName = "common.properties";
Path resourceDirectory = Paths.get("src","main","resources", "properties");
String absolutePath = resourceDirectory.toFile().getAbsolutePath();
final File file = new File(absolutePath.concat("/").concat(fileName));
if (file.exists()) {
try {
MutablePropertySources sources = env.getPropertySources();
sources.addFirst(new PropertiesPropertySource(fileName, PropertiesLoaderUtils.loadAllProperties(file.getName())));
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
throw new RuntimeException(ex.getMessage(), ex);
}
}
this.env = env;
return new PropertySourcesPlaceholderConfigurer();
}
答案2
得分: 0
感谢@Lemmy在解决这个问题上的指导。
我的最终解决方案是创建一个新的common-test-context.xml
文件,在其中我可以在类路径上的properties
文件夹中查找属性文件。我将此文件放置在src/test/resources/spring
文件夹中,并从src/main/resources/spring
文件夹中导入实际的common-context.xml
。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="classpath*:/spring/common-context.xml" />
<bean id="commonAppProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:/properties/common.properties</value>
</list>
</property>
</bean>
</beans>
英文:
Thanks to @Lemmy for the direction on how to solve this issue.
My final solution was to create a new common-test-context.xml
file where I can look for the property file in the properties folder on the class path. I placed this file in src/test/resources/spring
folder and imported the actual common-context.xml
from src/main/resources/spring
folder into it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="classpath*:/spring/common-context.xml" />
<bean id="commonAppProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:/properties/common.properties</value>
</list>
</property>
</bean>
</beans>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论