Unitils: How can it obtain database properties from Spring

送分小仙女□ 提交于 2019-12-24 10:25:55

问题


I am using Unitils with Spring for unit testing. I've configured Spring with datasource using a properties file.

My question is how can I use the same datasource or the same properties for Unitils?

Unitils expects a file in the classpath unitils.properties with database configuration parameters like url, user, password and driver.

I've tried to configure Unitils using the properties used in the Spring configuration as below but it is not working.

database.driverClassName=${jdbc.driver.class}

Thanks, Adi


回答1:


One potential solution... You could have your Spring configuration read its datasource parameters from the unitils.properties, instead of the other way around. Probably not ideal.

I believe unitils is using spring under the covers, so you might also try adding your datasource context in your unitils tests by using @SpringApplicationContext. If you could figure out the name of the datasource bean setup by unitils when it starts up, you could override it in your context (assuming the unitils datasource bean is created before the other spring beans are which may/may not be true.)

e.g.

@SpringApplicationContext({"correctDataSourceContext.xml"})

EDIT: Another option that will definitely work: https://stackoverflow.com/a/6561782/411229 Basically instantiate Unitils yourself and set the properties manually.




回答2:


Ryan answer is correct and helpful as well though I've used different approach.

I extended the class PropertiesDataSourceFactory ro override the methods as follows:

public class UnitilsDataSourceFactory extends PropertiesDataSourceFactory {

    @Override
    public void init(Properties configuration) {
        try {
            String[] configFiles = new String[] { "applicationContext-test.xml" };
            BeanFactory factory = new ClassPathXmlApplicationContext(configFiles);

            SystemPropertiesReader systemPropertiesReader = (SystemPropertiesReader) factory.getBean("systemPropertiesReader");
            Properties loadProperties = systemPropertiesReader.loadProperties();

            super.init(loadProperties);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public DataSource createDataSource() {
        DataSource dataSource = super.createDataSource();
        return dataSource;
    }

}

and also wrote a SystemPropertiesReader as:

public class SystemPropertiesReader {

    private Collection<Resource> resources;

    public void setResources(final Collection<Resource> resources) {
        this.resources = resources;
    }

    public void setResource(final Resource resource) {
        resources = Collections.singleton(resource);
    }

    @PostConstruct
    public Properties loadProperties() throws Exception {
        final Properties systemProperties = System.getProperties();
        for (final Resource resource : resources) {
            final InputStream inputStream = resource.getInputStream();
            try {
                systemProperties.load(inputStream);
            } finally {
                //
            }
        }

        return systemProperties;
    }

}

and added a bean with the properties file:

<bean id="systemPropertiesReader" class="uk.co.friendslife.eventmanager.domain.dao.SystemPropertiesReader">
            <property name="resource">
                <value>classpath:/META-INF/em/config/eventmanager_${database_name_lower}.properties</value>
            </property>
</bean>

add the following to unitils.properties:

org.unitils.database.config.DataSourceFactory.implClassName=x.y.UnitilsDataSourceFactory



回答3:


Just want to add some idea and im not sure if it is a best practice or not so correct me if theres something wrong.

  • MYPROJECT
    -src
    --TestPackage
    ---BaseServiceTest.class
    ---BlogspotServiceTest.class
    --hibernate.cfg.xml
    -web
    --WEB-INF
    ---blogspot-servlet-test.xml
    ---jdbc-test.properties

in my case I used my blogspot-servlet-test.xml to call or to create the datasource

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

     .... some bean configuration

    <bean id="propertyConfigurer" 
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
          p:location="file:web/WEB-INF/jdbc.properties"/>


    <bean id="dataSource"
          class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
          p:driverClassName="${jdbc.driverClassName}"
          p:url="${jdbc.databaseurl}"
          p:username="${jdbc.username}"
          p:password="${jdbc.password}"/>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${jdbc.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
     </bean>

     <!-- DAO'S -->
     <bean id="blogspotDAO" class="package.BlogspotDAOImpl"/>

     <!-- SERVICES -->
     <bean id="blogspotService" class="package.BlogspotServiceImpl"/>

     <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
     </bean>


     <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

MY jdbc-test.properties file

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQL5Dialect
jdbc.databaseurl=jdbc:mysql://127.0.0.1:3306/dbspringminiblogtest
jdbc.username=root
jdbc.password=

For hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://www.hibernate.org/dtd//hibernate-configuration-3.0.dtd">

    <hibernate-configuration>
        <session-factory>
            <mapping class="somePackage.entity.Author"/>
            <!-- Other Entity Class to be mapped -->

        </session-factory>
    </hibernate-configuration>

and i created BaseClass for me to lessen creating of multiple @SpringApplicationContext annotation and it is also use to configure common configuration needed in testing other class, just extends it.

@SpringApplicationContext({"file:web/WEB-INF/blogspot-servlet-test.xml"})
public class BaseServiceTest extends UnitilsJUnit4 {
}

i used @SpringApplicationContext to load the datasource and other bean configurations on my BaseClass and this is how i implement it.

Below : see Spring-Unitils Tutorial for more details

public class BlogspotServiceTest extends BaseServiceTest{

    @Mock
    @InjectInto(property = "blogspotDAO")
    @SpringBean("blogspotDAO")
    private BlogspotDAO blogspotDAOMock;

    @TestedObject
    @SpringBean("blogspotService")
    private BlogspotService blogspotServiceMock;

    @Test
    public void testAddBlogSpot() {
        assertNotNull("BlogspotService Not null",blogspotServiceMock);
    }
}

NOTE: please create unitils.properties and unitils-local.properties inside TestPackage to be able to run the program.

For @SpringBean explanation and other annotation please read :

Unitils-EasyMock



来源:https://stackoverflow.com/questions/9383096/unitils-how-can-it-obtain-database-properties-from-spring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!