使用Spring @PropertySource在JUnit测试中从src/main/resources中使用实际的属性文件。

huangapple go评论73阅读模式
英文:

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}"

测试用例无法找到所需的属性的一个原因是:

  1. PropertyPlaceholderConfigurer bean 引用了 {conf_folder_path}/common.properties,这是 Maven 构建系统将 src/main/resources/properties/common.properties 复制到的路径。
  2. 然而,在 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(&quot;classpath:properties/common.properties&quot;)
@ContextConfiguration(locations = { &quot;/spring/common-context.xml&quot; })
public class ConfigDAOImplTest {
	
	@Autowired
	private ConfigDAOImpl configDAO;

	@Spy
	private ContextParamDAO contextParamDAO = new ContextParamDAOImpl();

	private static final String SCHEMA_CONFIG = &quot;classpath:data/CONFIG_SCHEMA.sql&quot;;
	private static final String DATA_CONFIG = &quot;classpath:data/CONFIG_DATA.sql&quot;;

	@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

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
	xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:tx=&quot;http://www.springframework.org/schema/tx&quot; xmlns:batch=&quot;http://www.springframework.org/schema/batch&quot;
	xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
	xsi:schemaLocation=&quot;
		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&quot;&gt;

    &lt;bean id=&quot;commonAppProperties&quot;
		class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&gt;
		&lt;property name=&quot;ignoreResourceNotFound&quot; value=&quot;true&quot; /&gt;
		&lt;property name=&quot;ignoreUnresolvablePlaceholders&quot; value=&quot;true&quot; /&gt;
		&lt;property name=&quot;locations&quot;&gt;
			&lt;list&gt;
				&lt;value&gt;file:${conf_folder_path}/common.properties&lt;/value&gt;
			&lt;/list&gt;
		&lt;/property&gt;
	&lt;/bean&gt;

    &lt;bean id=&quot;configDAO&quot;
		class=&quot;com.myproject.common.dataaccess.impl.ConfigDAOImpl&quot; scope=&quot;step&quot;&gt;
		&lt;property name=&quot;jdbcTemplate&quot; ref=&quot;jdbcTemplate&quot; /&gt;
        &lt;property name=&quot;corePoolSize&quot; value=&quot;${threadpool.size}&quot;/&gt;
    &lt;/bean&gt;
&lt;/beans&gt;

When I run the test class, I get the following exception :

Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type &#39;java.lang.String&#39; to required type &#39;int&#39; for property &#39;corePoolSize&#39;; nested exception is java.lang.NumberFormatException: For input string: &quot;${threadpool.size}&quot;

One reason for the test case not being able to find the required property is because :

  1. 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.
  2. 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 = &quot;common.properties&quot;;
        Path resourceDirectory = Paths.get(&quot;src&quot;,&quot;main&quot;,&quot;resources&quot;, &quot;properties&quot;);
        String absolutePath = resourceDirectory.toFile().getAbsolutePath();
        final File file = new File(absolutePath.concat(&quot;/&quot;).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.

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
	xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:tx=&quot;http://www.springframework.org/schema/tx&quot; xmlns:batch=&quot;http://www.springframework.org/schema/batch&quot;
	xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
	xsi:schemaLocation=&quot;
		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&quot;&gt;

	&lt;import resource=&quot;classpath*:/spring/common-context.xml&quot; /&gt;
	
	
	&lt;bean id=&quot;commonAppProperties&quot;
		class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&gt;
		&lt;property name=&quot;ignoreResourceNotFound&quot; value=&quot;true&quot; /&gt;
		&lt;property name=&quot;ignoreUnresolvablePlaceholders&quot; value=&quot;true&quot; /&gt;
		&lt;property name=&quot;locations&quot;&gt;
			&lt;list&gt;
				&lt;value&gt;classpath:/properties/common.properties&lt;/value&gt;
			&lt;/list&gt;
		&lt;/property&gt;
	&lt;/bean&gt;
	
&lt;/beans&gt;

huangapple
  • 本文由 发表于 2020年4月8日 17:31:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/61097514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定