我有一个使用Spring3和Hibernate4的Web项目,现在我想在不使用xml文件的情况下测试DAO。为此,我创建了一个类,该类创建了一个LocalSessionFactoryBean,其中包含应用程序的xml文件中包含的数据和一个简单的测试类。
但是, localSessionFactoryBean.getObject()返回的 sessionFactory 为null。我一直在研究像this这样的例子,当我修改它们以便在没有Spring的情况下运行时它们会遇到同样的问题。你有什么想法吗?
这是准备sessionFactory的代码:
@Configuration
@Transactional
@EnableTransactionManagement
@ComponentScan({ "com.company" })
public class HibernateInitializator {
public SessionFactory getSessionFactory() {
Properties hibernateProperties = getHibernateProperties();
DataSource dataSource = getDatasourceConfiguration();
LocalSessionFactoryBean localSessionFactoryBean = generateSessionFactoryBean(new String[] { "com.company" },
dataSource, hibernateProperties);
SessionFactory sessionFactory = localSessionFactoryBean.getObject();
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return sessionFactory;
}
private DataSource getDatasourceConfiguration() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/dbName");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}
private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
Properties hibernateProperties) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan(basePackage);
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
return localSessionFactoryBean;
}
private static Properties getHibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
hibernateProperties.put("hibernate.show_sql", false);
hibernateProperties.put("hibernate.generate_statistics", false);
hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
hibernateProperties.put("hibernate.use_sql_comments", false);
return hibernateProperties;
}
}
这是一个使用它的简单测试类:
public class GenericDAOHibernateTest {
private GenericDAOHibernate dao;
@BeforeTest
private void testInitialization() {
dao = new GenericDAO();
HibernateInitializator initializator = new HibernateInitializator();
SessionFactory sessionFactory = initializator.getSessionFactory();
dao.setSessionFactory(sessionFactory);
}
@Test(description = "Checks that returns the user list ")
public void shouldReturnsUserList() throws SQLException, Exception {
List<Object[]> openResultSetList = dao.doSomeOperation();
...
}
}
答案 0 :(得分:12)
尝试添加此行
localSessionFactoryBean.afterPropertiesSet();
设置LocalSessionFactoryInstance
属性后的方法中的。你的方法将是
private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
Properties hibernateProperties) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan(basePackage);
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
// Added the below line
localSessionFactoryBean.afterPropertiesSet();
return localSessionFactoryBean;
}
此link可能会为问题增加更多洞察力。
根据文档,
public void afterPropertiesSet()抛出IOException
在BeanFactory设置了所有提供的bean属性(并且满足BeanFactoryAware和ApplicationContextAware)之后,由BeanFactory调用。 此方法允许bean实例仅在设置了所有bean属性时执行初始化,并在配置错误时抛出异常。
在您的情况下,我认为您需要手动在代码中调用它。
答案 1 :(得分:3)
我问过如何在没有xml文件的情况下执行此操作,@ Octopus提出的解决方案解决了我遇到的问题。但是,在修复后出现其他错误的事务......所以我决定以不同的方式做这件事,不干扰应用程序。
为此,我在/ src / test / resources中创建了一个xml文件的简化版本,删除了许多配置,如c3p0的一个,并对这些值进行硬编码,以便在应用程序的属性文件发生更改时测试不会失败。
这是xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<!-- Spring DataSource -->
<bean id="testDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/testDatabase" />
<property name="username" value="testUsername" />
<property name="password" value="testPassword" />
</bean>
<!-- Hibernate 4 SessionFactory -->
<bean id="testSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="testDataSource">
<property name="packagesToScan" value="com.company" />
<property name="hibernateProperties">
<props>
<!-- Hibernate basic configuration -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.use_sql_comments">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="testDataSource" />
<property name="sessionFactory" ref="testSessionFactory" />
</bean>
<context:annotation-config />
<tx:annotation-driven />
<!-- Initialization of DAOs -->
<bean id="userDao" name="userDao" class="com.company.dao.UserDAOHibernate" autowire="byName"/>
...
</beans>
在测试类中,我使用了JUnit,因为尽管我尝试扩展AbstractTestNGSpringContextTests,但还是没有设法使用TestNG。我建议使用JUnit 4.4版本而不是更新的版本,因为它有类似 AssumptionViolatedException 的类,由spring-test 2.5使用。
这是代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/application-config-tests.xml" })
public class SimpleUserDAOTest {
@Autowired
private UserDAO dao;
@Autowired
private SessionFactory sessionFactory;
@Before
public void setUp() throws Exception {
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(sessionFactory.openSession()));
}
@After
public void tearDown() throws Exception {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
@Test
public void shouldReturnActiveUsers() {
List<User> userList = dao.getActiveUsers();
...
}
}
我希望这对您未来的发展有所帮助
答案 2 :(得分:0)
当您使用Spring 3+和Hibernate 4时,我建议您使用更好的方法,将所有内容定义为带注释的Spring配置,并且这项工作顺利进行。
下面是详细的代码,只需复制并粘贴到您的项目中,您可以在DAO层或任何弹簧组件的任何位置Autowire
SessionFactory:)
@Configuration
@Import(HibernateConfig.class)
@EnableWebMvc
@ComponentScan(basePackages = "com.mypackages")
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.parameterName("mediaType").ignoreAcceptHeader(true)defaultContentType(MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
}
@Bean(name = "validator")
public Validator validator() {
return new LocalValidatorFactoryBean();
}
}
然后定义HibernateConfig
,如下所示:
@Configuration
@EnableTransactionManagement
@EnableAspectJAutoProxy
@PropertySource({"classpath:app.properties"})
@ComponentScan(basePackages = "com.mypackages")
public class HibernateConfig {
@Value(Constants.HIBERNATE_DIALECT)
private String hibernateDialect;
@Autowired
private DataSource dataSource;
@Bean(name = "appProperty")
public static PropertySourcesPlaceholderConfigurer appProperty() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() throws Exception {
Properties properties = new Properties();
properties.put(Constants.HIBERNATE_DIALECT_PROPERTY,
hibernateDialect);
properties.put(Constants.HIBERNATE_SHOW_SQL_PROPERTY,
"false");
properties
.put(Constants.HIBERNATE_CURRENT_SESSION_CONTEXT_CLASS_PROPERTY,
"thread");
properties
.put("dynamic-update","true");
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setPackagesToScan(new String[] { Constants.DOMAIN_MODEL_PACKAGE });
factory.setDataSource(dataSource);
factory.setHibernateProperties(properties);
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager() throws Exception {
return new HibernateTransactionManager(getSessionFactory());
}
}
然后定义JndiConfig
,如下所示:
@Configuration
public class JndiConfig {
@Value(Constants.DRIVER_CLASS)
private String driverClassName;
@Value(Constants.DATABASE_URL)
private String databaseURL;
@Value(Constants.USER_NAME)
private String username;
@Value(Constants.PASSWORD)
private String password;
@Value(Constants.MAX_ACTIVE)
private int maxActive;
@Value(Constants.MAX_IDLE)
private int maxIdle;
@Value(Constants.MAX_WAIT)
private long maxWait;
@Value(Constants.MIN_IDLE)
private int minIdle;
@Value(Constants.INITIAL_SIZE)
private int initialSize;
@Value(Constants.TIME_BETWEEN_EVICTION)
private long timeBetweenEvictionRunsMillis;
@Bean(name = "dataSource")
public DataSource dataSource() throws Exception {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(databaseURL);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
dataSource.setValidationQuery("SELECT 1");
dataSource.setMaxActive(maxActive);
dataSource.setMaxIdle(maxIdle);
dataSource.setMaxWait(maxWait);
dataSource.setMinIdle(minIdle);
dataSource
.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
return dataSource;
}
}