0

总之,我正在尝试为使用 Hibernate 的 Dao 编写单元测试。我也在使用 Spring,所以我尝试扩展 AbstractTransactionalDataSourceSpringContextTests 并使用 DBUnit 在 onSetUpInTransaction 方法中的每个测试之前将数据插入数据库。

从我的日志中,我可以看到 DbUnit 能够成功地将数据插入 onSetUpInTransaction 就好了。但是,当我运行使用 Dao(以及因此使用 Hibernate)的测试方法来尝试访问该数据(testGetPersonById2)时,找不到数据,即使所有这些都应该发生在同一个事务中。在测试方法完成运行(失败)后,我看到来自 AbstractTransactionalDataSourceSpringContextTests 的日志语句表明事务确实得到了正确回滚。

似乎 onSetUpInTransaction 和 Hibernate 会话必须使用不同的事务,但我不知道为什么。有没有人有这样的例子?关于我缺少什么的建议?

这是我到目前为止所得到的:

public class PersonDaoTest extends AbstractTransactionalDataSourceSpringContextTests{

    private Log logger = LogFactory.getLog(PersonDaoTest.class);

    private PersonDaoImpl personDao;

    @Override
    public void onSetUpInTransaction() throws Exception {
    // Load test data using DBUnit
    super.onSetUpBeforeTransaction();
        DataSource ds = jdbcTemplate.getDataSource()
    Connection con = DataSourceUtils.getConnection(ds);
    IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
    DatabaseConfig config = dbUnitCon.getConfig();
    config.setFeature("http://www.dbunit.org/features/qualifiedTableNames",
        true);

        //This dataset contains a single entry in the Persons table,
        // a new person with Id = 998877665, it gets inserted successfully
    IDataSet dataSet = new FlatXmlDataSet(new FileInputStream(
        "./PersonDaoTest.xml"));
    logger.warn("dataSet = " + dataSet);
    try {
        DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
        SessionFactoryUtils.getSession(getSessionFactory(), false).flush();

    } finally {
        DataSourceUtils.releaseConnection(con, ds);
    }

    }

     //This test PASSES, because the Person with Id = 9 already
     //exists in the database, it does not rely on the data being set up in the        
     // onSetUpInTransaction method 
     @Test
     public void testGetPersonById() {

     Person person = personDao.findById(9L);
     assertNotNull("person should not be null", person);

     }

    //This test FAILS at the assertNotNull line, because
    //no Person with Id = 998877665 exists in the database,
    //even though that Person was inserted 
    //in the onSetUpInTransaction  method - it seems
    //that hibernate cannot see that insertion.
    @Test
    public void testGetPersonById2() {

    Person person = personDao.findById(998877665L);
    assertNotNull("person should not be null", person);

    }

更新:这是我的弹簧配置:

<bean id="propertyConfigurer"       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
  <constructor-arg>
    <bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName">
     <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
       <value>${jdbc.url}</value>
    </property>
    <property name="username">
       <value>${jdbc.username}</value>
    </property>
     <property name="password">
       <value>${jdbc.password}</value>
      </property>
   </bean>
  </constructor-arg>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>


<!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource"><ref bean="dataSource"/></property>

        <property name="configLocation">
             <value>classpath:hibernate.cfg.xml</value>
        </property>

        <property  name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                <prop key="hibernate.cache.query_cache_factory">org.hibernate.cache.StandardQueryCacheFactory</prop>
            </props>
        </property>
    </bean>

    <!-- The Hibernate interceptor 
    <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>-->

     <bean id="personDao" class="my.dao.PersonDaoImpl">
        <property name="sessionFactory"><ref bean="sessionFactory"/></property>         
    </bean> 
4

2 回答 2

1

我花了更多时间来处理这个问题,但在尝试使用 onSetUpInTransaction 方法时从未找到任何有效的方法。我最终改用 onSetUpBeforeTransaction 和 onTearDownAfterTransaction 。这并不完全理想,因为 onSetUpBeforeTransaction 方法最终会将其数据插入提交到数据库,然后必须在 onTearDownAfterTransaction 中清理该数据。然而,测试本身仍然可以插入和更新他们想要的所有数据,并让这些更改全部回滚,因为每个测试仍然在自己的事务中运行。所以,当测试插入新数据时,我不需要做任何特别的清理工作,这意味着我无论如何都达到了我的目标之一!

于 2010-06-30T15:05:36.120 回答
1

我有一个类似的问题。这就是我解决它的方法。我在我的抽象测试用例类中添加了一个代码,然后我添加了一个名为“dataSource”的数据源,它允许我使用它来插入我的测试数据并使用该数据源创建我的测试 sql。单独的数据源 datasource1 和 datasource2 被正确注入到我的 dao bean 中,没有任何问题。

@Override
protected String[] getConfigLocations() 
{
    setAutowireMode(AUTOWIRE_BY_NAME);
    setDependencyCheck(false);
    return new String[] { "classpath:configuration/myappxxx-test-application-context.xml" };
}
于 2012-12-12T16:08:15.520 回答