I am using TestNG together with Spring and JPA. So far I am using to test database stuff my test class which extends AbstractTransactionalTestNGSpringContextTests
. With @TransactionConfiguration(defaultRollback = true)
everything works fine and I do not need to cary about cleanup. Spring creates a default transaction on the beginning of each of my test method which is than rollbacked. This is a very neat trick to solve famous "Transactional tests considered harmful" problem.
Unfortunately I need for one method in this class (one test) to not have this default transaction. This is because this test method simulates batch processing and I have multiple transactions inside it which are in production independent. The only way I was able to simulate and solve problem is to configure those inner transactions with Propagation.REQUIRES_NEW
but this I do not want to have in production code.
Is there some way to disable Spring transaction for my particular test method (so I do not need to use Propagation.REQUIRES_NEW
but Propagation.REQUIRED
in my service methods) ?
I have found that by executing the body of my test in separate thread prevent Spring from transaction. So the workaround solution is something like:
@ContextConfiguration(classes = { test.SpringTestConfigurator.class })
@TransactionConfiguration(defaultRollback = false)
@Slf4j
@WebAppConfiguration
public class DBDataTest extends AbstractTransactionalTestNGSpringContextTests {
/**
* Variable to determine if some running thread has failed.
*/
private volatile Exception threadException = null;
@Test(enabled = true)
public void myTest() {
try {
this.threadException = null;
Runnable task = () -> {
myTestBody();
};
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(task);
executor.shutdown();
while (!executor.isTerminated()) {
if (this.threadException != null) {
throw this.threadException;
}
}
if (this.threadException != null) {
throw this.threadException;
}
} catch (Exception e) {
log.error("Test has failed.", e);
Assert.fail();
}
}
public void myTestBody() {
try {
// test body to do
}
catch (Exception e) {
this.threadException = e;
}
}
}