Spring集成测试不会回滚 [英] Spring integration test does not roll back

查看:187
本文介绍了Spring集成测试不会回滚的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Spring + Hibernate + H2。我在集成测试中执行数据库操作(通过调用服务类)。我希望Spring在每种测试方法之后回滚这些更改,但是我无法使其工作。起初我使用MySQL(与MyISAM,不支持交易),但在改为H2后,问题依然存在。我尝试了几个DataSource定义(在阅读之后,它必须是支持XA的),但似乎没有任何帮助。



我使用 http://code.google.com/p/generic-dao/ 为我的DAO-classes和@Transactional-annotations我的服务层(如果我删除它们,我得到以下错误:javax.persistence.TransactionRequiredException:没有事务正在进行中)。

我的测试类看起来像这样:

  @ContextConfiguration(classpath:... spring.xml)
@Transactional
@TransactionConfiguration (transactionManager =transactionManager,defaultRollback = true)
public class DemoServiceTest extends AbstractTestNGSpringContextTests {
@Autowired
DemoService demoService;

@Test
public void addTest()
{
int size = demoService.findAll()。size();
Test coach = new Test();
test.setName(Test);
testService.save(test);
Assert.assertEquals(size + 1,testService.findAll()。size());


$ / code $ / pre

这里是我的spring-configuration:

 <! - < bean id =myDataSourceclass =org.apache.commons.dbcp.BasicDataSource> - > 
<! - < property name =driverClassNamevalue =org.h2.Driver/> - >
<! - < property name =urlvalue =jdbc:h2:〜/ test/> - >
<! - < property name =usernamevalue =sa/> - >
<! - < property name =passwordvalue =/> - >
<! - < / bean> - >
<! - < bean id =myDataSourceclass =com.mchange.v2.c3p0.ComboPooledDataSource> - >
<! - < property name =driverClassvalue =org.h2.Driver/> - >
<! - < property name =jdbcUrlvalue =jdbc:h2:〜/ test/> - >
<! - < property name =uservalue =sa/> - >
<! - < property name =passwordvalue =/> - >
<! - < / bean> - >

< bean id =myDataSourceclass =com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean>
< property name =uniqueResourceNamevalue =test/>
< property name =driverClassNamevalue =org.h2.Driver/>
< property name =urlvalue =jdbc:h2:〜/ test/>
< property name =uservalue =sa/>
< property name =passwordvalue =/>
< property name =maxPoolSizevalue =20/>
< property name =reapTimeoutvalue =300/>
< / bean>

< bean id =demoDAOclass =... DemoDAOImpl/>
< bean id =demoServiceclass =... DemoServiceImpl/>

< bean id =entityManagerFactory
class =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
< property name =persistenceUnitNamevalue =test/>
< property name =persistenceXmlLocationvalue =classpath:persistence.xml/>
< property name =dataSourceref =myDataSource/>
< property name =loadTimeWeaver>
< bean
class =org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver/>
< / property>
< property name =jpaVendorAdapterref =vendorAdapter/>
< / bean>

< bean id =vendorAdapter
class =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter>
< property name =databasevalue =H2/>
< property name =showSqlvalue =true/>
< property name =generateDdlvalue =true/>
< / bean>

< bean id =transactionManagerclass =org.springframework.orm.jpa.JpaTransactionManager>
< property name =entityManagerFactoryref =entityManagerFactory/>
< / bean>

< bean id =searchProcessorclass =com.googlecode.genericdao.search.jpa.JPASearchProcessor>
< constructor-arg ref =metadataUtil/>
< / bean>

< bean id =metadataUtil
class =com.googlecode.genericdao.search.jpa.hibernate.HibernateMetadataUtil
factory-method =getInstanceForEntityManagerFactory>
< constructor-arg ref =entityManagerFactory/>
< / bean>

< bean
class =org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor/>
< tx:annotation-driven />

这就是我的服务实现:

  @Transactional 
public class TestServiceImpl implements TestService {
private TestDAO< Test,Long>道;

@Autowired
public void setDao(TestDAO< Test,Long> dao){
this.dao = dao;
}

public void save(Test test){
dao.persist(test);
dao.flush();
}

public List< Test> findAll(){
return dao.findAll();

$ b $ public Test findByName(String name){
if(name == null)
return null;
return dao.searchUnique(new Search()。addFilterEqual(name,name));




$ b编辑:dao.persist() - 方法基本上从genericdao封装对以下方法的调用(em返回当前的EntityManager):

  / ** 
*< ; p为H.
*使暂时实例持久化并将其添加到数据存储区。如果关联映射
*和cascade =persist,则
*操作会级联到关联的实例。如果实体已经存在,则抛出错误。
*
*< p>
*不保证立即为对象分配标识符
*。使用< code>持久< / code>数据存储区生成的ID可能不会被
*拉到刷新时间。
* /
protected void _persist(Object ... entities){
for(Object entity:entities){
if(entity!= null)
em ).persist(实体);


$ / code $ / pre

一切正常,但更改仍保留在数据库中。任何想法?我认为你需要扩展AbstractTransactionalTestNGSpringContextTests而不是AbstractTestNGSpringContextTests。

解决方案

I'm using Spring + Hibernate + H2. I do database operations in my integration tests (by calling a service class). I want Spring to rollback the changes after each test method, but I can't get it to work. At first I used MySQL (with MyISAM, which doesn't support transaction), but after changing to H2 the problem remains. I tried several DataSource-definitions (after reading that it must be XA-aware), but nothing seems to help.

I use http://code.google.com/p/generic-dao/ for my DAO-classes and @Transactional-annotations in my service layer (if I remove them, I get the following error: javax.persistence.TransactionRequiredException: no transaction is in progress).

My test classes look like this:

@ContextConfiguration("classpath:...spring.xml")
@Transactional
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
public class DemoServiceTest extends AbstractTestNGSpringContextTests{
@Autowired
private DemoService demoService;

@Test
public void addTest()
{
    int size = demoService.findAll().size();
    Test coach = new Test();
    test.setName("Test");
    testService.save(test);
    Assert.assertEquals(size+1,testService.findAll().size());
}
}

Here's my spring-configuration:

<!-- <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"> -->
<!-- <property name="driverClassName" value="org.h2.Driver" /> -->
<!-- <property name="url" value="jdbc:h2:~/test" /> -->
<!-- <property name="username" value="sa" /> -->
<!-- <property name="password" value="" /> -->
<!-- </bean> -->
<!--    <bean id="myDataSource" class=" com.mchange.v2.c3p0.ComboPooledDataSource"> -->
<!--        <property name="driverClass" value="org.h2.Driver" /> -->
<!--        <property name="jdbcUrl" value="jdbc:h2:~/test" /> -->
<!--        <property name="user" value="sa" /> -->
<!--        <property name="password" value="" /> -->
<!--    </bean> -->

<bean id="myDataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean">
    <property name="uniqueResourceName" value="test" />
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:~/test" />
    <property name="user" value="sa" />
    <property name="password" value="" />
    <property name="maxPoolSize" value="20" />
            <property name="reapTimeout" value="300" />
</bean>

<bean id="demoDAO" class="...DemoDAOImpl" />
<bean id="demoService" class="...DemoServiceImpl" />

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="test" />
    <property name="persistenceXmlLocation" value="classpath:persistence.xml" />
    <property name="dataSource" ref="myDataSource" />
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="jpaVendorAdapter" ref="vendorAdapter" />
</bean>

<bean id="vendorAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="H2" />
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="searchProcessor" class="com.googlecode.genericdao.search.jpa.JPASearchProcessor">
    <constructor-arg ref="metadataUtil" />
</bean>

<bean id="metadataUtil"
    class="com.googlecode.genericdao.search.jpa.hibernate.HibernateMetadataUtil"
    factory-method="getInstanceForEntityManagerFactory">
    <constructor-arg ref="entityManagerFactory" />
</bean>

<bean
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<tx:annotation-driven />

And that's my service implementation:

@Transactional
public class TestServiceImpl implements TestService {
    private TestDAO<Test,Long> dao;

    @Autowired
    public void setDao(TestDAO<Test,Long> dao) {
        this.dao = dao;
    }

    public void save(Test test) {
        dao.persist(test);
        dao.flush();
    }

    public List<Test> findAll() {
        return dao.findAll();
    }

    public Test findByName(String name) {
        if (name == null)
                return null;
        return dao.searchUnique(new Search().addFilterEqual("name", name));
    }
}

EDIT: The dao.persist()-method basically encapsulates the call to the following method from genericdao (em returns the current EntityManager):

/**
 * <p>
 * Make a transient instance persistent and add it to the datastore. This
 * operation cascades to associated instances if the association is mapped
 * with cascade="persist". Throws an error if the entity already exists.
 * 
 * <p>
 * Does not guarantee that the object will be assigned an identifier
 * immediately. With <code>persist</code> a datastore-generated id may not
 * be pulled until flush time.
 */
protected void _persist(Object... entities) {
    for (Object entity : entities) {
        if (entity != null)
            em().persist(entity);
    }
}

Everything works fine, but the changes remain in the database. Any ideas?

解决方案

I think you need to extend from AbstractTransactionalTestNGSpringContextTests instead of AbstractTestNGSpringContextTests.

这篇关于Spring集成测试不会回滚的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆