Skip to content

Instantly share code, notes, and snippets.

@ttddyy
Created December 22, 2020 19:02
Show Gist options
  • Save ttddyy/8bf8bc0ba49b75dbdb122973cfa6ec7f to your computer and use it in GitHub Desktop.
Save ttddyy/8bf8bc0ba49b75dbdb122973cfa6ec7f to your computer and use it in GitHub Desktop.
Class level rollback TestExecutionListener
package com.example;
import javax.sql.DataSource;
import com.example.TransactionTest.MyTestExecutionListener;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.NamedInheritableThreadLocal;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TestContextTransactionUtils;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* @author Tadaya Tsuyukubo
*/
@SpringJUnitConfig()
@TestMethodOrder(OrderAnnotation.class)
//@Transactional
//@TestExecutionListeners(listeners = MyTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, MyTestExecutionListener.class })
//@TestInstance(Lifecycle.PER_CLASS)
class TransactionTest {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
@Order(1)
void first() {
System.out.println("Running first test");
this.jdbcTemplate.execute("INSERT INTO students VALUES (1, 'FOO')");
int count = JdbcTestUtils.countRowsInTable(jdbcTemplate, "students");
assertThat(count).isEqualTo(1);
}
@Test
@Order(2)
void second() {
System.out.println("Running second test");
int count = JdbcTestUtils.countRowsInTable(jdbcTemplate, "students");
assertThat(count).isEqualTo(1);
}
@Slf4j
static class MyTestExecutionListener extends AbstractTestExecutionListener {
private static final ThreadLocal<MyTransactionContext> currentTransactionContext =
new NamedInheritableThreadLocal<>("Test Transaction Context");
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
log.info("Start Transaction - beforeTestClass");
PlatformTransactionManager tm = TestContextTransactionUtils.retrieveTransactionManager(testContext, null);
TransactionDefinition txDefinition = new DefaultTransactionDefinition();
TransactionStatus txStatus = tm.getTransaction(txDefinition);
MyTransactionContext txContext = new MyTransactionContext(testContext, txDefinition, txStatus, tm);
MyTestExecutionListener.currentTransactionContext.set(txContext);
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
log.info("Rollback Transaction - afterTestClass");
MyTransactionContext txContext = MyTestExecutionListener.currentTransactionContext.get();
txContext.getTransactionManager().rollback(txContext.getTxStatus());
}
@Data
static class MyTransactionContext {
private final TestContext testContext;
private final TransactionDefinition transactionDefinition;
private final TransactionStatus txStatus;
private final PlatformTransactionManager transactionManager;
}
}
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement
static class MyConfig {
@Bean
PlatformTransactionManager txManager(DataSource dataSource) {
return new JdbcTransactionManager(dataSource);
}
@Bean
JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
InitializingBean populator(JdbcTemplate jdbcTemplate) {
return () -> jdbcTemplate.execute("CREATE TABLE students (id int, name varchar(20))");
}
@Bean
EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
@Bean
DisposableBean cleanup(EmbeddedDatabase ds) {
return ds::shutdown;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment