@ Test 之后的回滚事务

首先,我在 StackOverflow 上找到了很多关于这个问题的帖子,但是没有一个对我有帮助,所以很抱歉问一个可能重复的问题。

我使用 spring-test 运行 JUnit 测试,我的代码如下所示

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {})
public class StudentSystemTest {


@Autowired
private StudentSystem studentSystem;


@Before
public void initTest() {
// set up the database, create basic structure for testing
}


@Test
public void test1() {
}
...
}

我的问题是我希望我的测试不要影响其他的测试。 因此,我想为每个测试创建一些类似于回滚的东西。 我找了很久,但是一无所获。 我正在使用 Hibernate 和 MySql

147053 次浏览

You need to run your test with a Spring context and a transaction manager, e.g.,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/your-applicationContext.xml"})
@TransactionConfiguration(transactionManager="txMgr")
public class StudentSystemTest {


@Test
public void testTransactionalService() {
// test transactional service
}


@Test
@Transactional
public void testNonTransactionalService() {
// test non-transactional service
}
}

See chapter 3.5.8. Transaction Management of the Spring reference for further details.

Just add @Transactional annotation on top of your test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"testContext.xml"})
@Transactional
public class StudentSystemTest {

By default Spring will start a new transaction surrounding your test method and @Before/@After callbacks, rolling back at the end. It works by default, it's enough to have some transaction manager in the context.

From: 10.3.5.4 Transaction management (bold mine):

In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener. Note that TransactionalTestExecutionListener is configured by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for transactions, however, you must provide a PlatformTransactionManager bean in the application context loaded by @ContextConfiguration semantics. In addition, you must declare @Transactional either at the class or method level for your tests.

The answers mentioning adding @Transactional are correct, but for simplicity you could just have your test class extends AbstractTransactionalJUnit4SpringContextTests.

You can disable the Rollback:

@TransactionConfiguration(defaultRollback = false)

Example:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class Test {
@PersistenceContext
private EntityManager em;


@org.junit.Test
public void menge() {
PersistentObject object = new PersistentObject();
em.persist(object);
em.flush();
}
}

I know, I am tooooo late to post an answer, but hoping that it might help someone. Plus, I just solved this issue I had with my tests. This is what I had in my test:

My test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "path-to-context" })
@Transactional
public class MyIntegrationTest

Context xml

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>

I still had the problem that, the database was not being cleaned up automatically.

Issue was resolved when I added following property to BasicDataSource

<property name="defaultAutoCommit" value="false" />

Hope it helps.

Aside: attempt to amend Tomasz Nurkiewicz's answer was rejected:

This edit does not make the post even a little bit easier to read, easier to find, more accurate or more accessible. Changes are either completely superfluous or actively harm readability.


Correct and permanent link to the relevant section of documentation about integration testing.

To enable support for transactions, you must configure a PlatformTransactionManager bean in the ApplicationContext that is loaded via @ContextConfiguration semantics.

@Configuration
@PropertySource("application.properties")
public class Persistence {
@Autowired
Environment env;


@Bean
DataSource dataSource() {
return new DriverManagerDataSource(
env.getProperty("datasource.url"),
env.getProperty("datasource.user"),
env.getProperty("datasource.password")
);
}


@Bean
PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}

In addition, you must declare Spring’s @Transactional annotation either at the class or method level for your tests.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Persistence.class, SomeRepository.class})
@Transactional
public class SomeRepositoryTest { ... }

Annotating a test method with @Transactional causes the test to be run within a transaction that will, by default, be automatically rolled back after completion of the test. If a test class is annotated with @Transactional, each test method within that class hierarchy will be run within a transaction.

In addition to adding @Transactional on @Test method, you also need to add @Rollback(false)