问题
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