代码之家  ›  专栏  ›  技术社区  ›  elduff

使用AbstractTransactionalDatasourceSpringContextTests和Hibernate&DBUnit-找不到插入的数据

  •  0
  • elduff  · 技术社区  · 16 年前

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

    从我的日志中,我可以看到DBUnit能够成功地将数据插入OnSetPinTransaction中,这很好。但是,当我运行一个使用DAO(因此是Hibernate)尝试访问该数据的测试方法(testGetPersonByID2)时,没有找到数据,即使所有这些 应该 发生在同一个事务中。在测试方法完成运行(失败)后,我看到AbstractTransactionalDatasourceSpringContextTests中的日志语句,该事务确实被正确回滚。

    看起来OnSetPinTransaction和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> 
    
    2 回复  |  直到 13 年前
        1
  •  1
  •   elduff    16 年前

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

        2
  •  1
  •   user1456599    13 年前

    我也有类似的问题。我就是这样解决的。 我在抽象测试用例类中添加了一个代码 然后我添加了一个名为“data source”的数据源,它允许我使用它插入我的测试数据,并使用该数据源创建测试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" };
    }
    
    推荐文章