использование AbstractTransactionalDataSourceSpringContextTests с Hibernate & DbUnit - вставленные данные не найдены - PullRequest
0 голосов
/ 29 июня 2010

Все, Я пытаюсь написать модульный тест для Dao, который использует Hibernate. Я также использую Spring, поэтому я пытаюсь расширить AbstractTransactionalDataSourceSpringContextTests, а также использовать DBUnit для вставки данных в базу данных перед каждым тестом в методе onSetUpInTransaction.

Из моих логов я вижу, что DbUnit может успешно вставлять данные в onSetUpInTransaction очень хорошо. Однако, когда я запускаю тестовый метод, который использует Dao (и, следовательно, Hibernate), чтобы попытаться получить доступ к этим данным (testGetPersonById2), данные не найдены, даже если все это должно происходить в та же транзакция. После того, как тестовый метод завершает работу (он терпит неудачу), я вижу инструкцию log из 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> 

Ответы [ 2 ]

1 голос
/ 12 декабря 2012

У меня была похожая проблема.вот как я это решил.Я добавил код в свой абстрактный класс testcase, затем добавил источник данных с именем «dataSource», который позволил мне использовать его для вставки моих тестовых данных и создания моих тестовых sqls с использованием этого источника данных.Отдельные источники данных datasource1 и datasource2 были правильно введены в мои компоненты beo без каких-либо проблем.

@Override
protected String[] getConfigLocations() 
{
    setAutowireMode(AUTOWIRE_BY_NAME);
    setDependencyCheck(false);
    return new String[] { "classpath:configuration/myappxxx-test-application-context.xml" };
}
1 голос
/ 30 июня 2010

Я потратил на это больше времени и так и не смог найти ничего, что сработало бы при попытке использовать метод onSetUpInTransaction. В итоге я перешел на использование onSetUpBeforeTransaction и onTearDownAfterTransaction. Это не совсем идеально, потому что метод onSetUpBeforeTransaction в конечном итоге фиксирует свои вставки данных в базу данных, и эти данные затем должны быть очищены в onTearDownAfterTransaction. Однако сами тесты по-прежнему могут вставлять и обновлять данные по своему усмотрению и откатывать все эти изменения, поскольку каждый тест по-прежнему работает в своей собственной транзакции. Поэтому мне не нужно делать ничего особенного для очистки, когда тест вставляет новые данные, что означает, что я все равно достиг одной из своих целей!

...