Spring @transaction not working as expected in junit in non debug mode

All MyService methods are transactional. The junit test below, gets count of items, saves a new item, and gets count of items to make sure that counts has been incremented by 1.

public class MyTest extends ServiceTest{

    1. int countBefore = myService.getCount();    //return n
    2. myService.add(item);                       //item is really added to DB
    3. int countAfter  = myService.getCount();    //return n (sometimes n+1)
}

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED)
getCount(){…}

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE)
add(){…}

@Ignore
@ContextConfiguration(locations = { "file:src/main/resources/xxx-context.xml", 
                                    "file:src/main/resources/xxx-data.xml", 
                                    "file:src/main/resources/xxx-services.xml"  })
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = false)
@TestExecutionListeners( {  DependencyInjectionTestExecutionListener.class,
                            DirtiesContextTestExecutionListener.class,
                            TransactionalTestExecutionListener.class,
                            TestListener.class})

public class ServiceTest extends AbstractUT{

@Ignore
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( {TestListener.class})
public class AbstractUT{

When debugging (3.) returns n+1 which is what I want. But when running the test without debug I get n.

Even sometimes when running the test I get n+1 and next time I get n and when comparing the std output between the two execution, it looks exactly the same. I have enabled log4j.logger.org.springframework.transaction=TRACE and I can see:

Initializing transaction synchronization
Getting transaction for MyService.getCount
...
Completing transaction for MyService.getCount
Clearing transaction synchronization

...

Initializing transaction synchronization
Getting transaction for MyService.add
...
Completing transaction for MyService.add
Clearing transaction synchronization

...

Initializing transaction synchronization
Getting transaction for MyService.getCount
...
Completing transaction for MyService.getCount
Clearing transaction synchronization

So transactions are being executed one after the other, but how is possible that (3.) don't see the saved item?

Transaction managment is setup in my test class as per: https://stackoverflow.com/a/28657650/353985

How can I find what is going wrong? Thanks!


Had similar issue, but in my case it did not rollback. It seems that you forgot to add @Transactional. From documentation (link)

Transaction management

In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener which is configured by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for transactions, however, you must configure a PlatformTransactionManager bean in the ApplicationContext that is loaded via @ContextConfiguration semantics (further details are provided below). In addition, you must declare Spring's @Transactional annotation either at the class or method level for your tests.

Here is example form the link above.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional
public class FictitiousTransactionalTest {

@BeforeTransaction
public void verifyInitialDatabaseState() {
    // logic to verify the initial state before a transaction is started
}

@Before
public void setUpTestDataWithinTransaction() {
    // set up test data within the transaction
}

@Test
// overrides the class-level defaultRollback setting
@Rollback(true)
public void modifyDatabaseWithinTransaction() {
    // logic which uses the test data and modifies database state
}

@After
public void tearDownWithinTransaction() {
    // execute "tear down" logic within the transaction
}

@AfterTransaction
public void verifyFinalDatabaseState() {
    // logic to verify the final state after transaction has rolled back
}

}


A solution I found till now to pass test is to put assert in afterTransaction method

public class MyTest extends ServiceTest{

@Test
public void test(){
    1. int countBefore = myService.getCount();    //return n
    2. myService.add(item);                       //item is really added to DB
}
@AfterTransaction
public void verifyFinalDatabaseState() {
    3. int countAfter  = myService.getCount();    //return n (sometimes n+1) 
                                                  //Now always return n+1
}

I would have asked this in a comment but since my reputation does not allow it, I would just try to provide an answer.

It is possible that your are using and ORM that caches the results of count query. Depending how your add/getCount methods are implemented and the configurations of the ORM and datasource, on your second invocation of getCount, you might get a cached value obtained during first invocation of getCount.

This does not explain however why in debug mode you always get the correct result.

链接地址: http://www.djcxy.com/p/24962.html

上一篇: Ruby改进了微妙之处

下一篇: 在非调试模式下,Spring @transaction在junit中没有像预期的那样工作