Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@NotTransactional alternatives

I'm working on a unit test which commits information through a DAO to a Oracle database, and then retrieves it and checks everything is unchanged.

There are other unit tests in the test class, and at the top of the class I have:

@TransactionConfiguration (defaultRollback = true)

I'd like to know how I can remove the @NotTransactional. I'm not specifying Transactional on the class, so no tests should be like that by default. Since this is it's own test, I don't know if the @BeforeTransaction (or After) annotations would be correct.

The biggest problem is that without the @NotTransactional, it appears as though the unsubscribe() function isn't ran. (the trash flag is unchanged.)

Running the test again, with @rollback=false and @NonTransactional present, I see the trash flag correctly set to true, in the database after the test is finished.

@RunWith (SpringJUnit4ClassRunner.class)
@TransactionConfiguration (defaultRollback = true)
public class DatabaseTest {

    @Autowired (required = true)
    private FooDao<Foo> fooDao;

    @Autowired (required = true)
    private FooService fooService;

    // other tests here that are marked @Transactional.

    @Test
    @NotTransactional
    public void testDelete() {
        Foo foo = new foo();
        foo.setTrashFlag(false);
        foo.setId(123);

        fooDao.create(foo);

        Foo fooFromDb = fooService.getFromDbById(123);
        assertNotNull(fooFromDb);

        fooService.unsubscribe(123);   // among other things, 
                                       // **sets trash flag to true.**

     // sqlSession.flushStatements();  // doesn't seem to commit the unsubscribe action


        // getFromDbById() returns ONLY Foos with trash set to false, so we expect
        // nothing returned here as we've just set trash to true, using unsubscribe().

        Foo trashedFoo = fooService.getFromDbById(123);   
        assertNull(trashedFoo);

Thanks!

like image 877
iank Avatar asked Mar 18 '13 21:03

iank


2 Answers

I don't know if this is really on-topic, but I used @NotTransactional for methods that had a transactional base class. Spring says to split the tests in transactional and non-transactional, but I found out that in my case simply adding the following to the method just disabled transactions and let me delete the deprecated annotation:

@Transactional(propagation = Propagation.NEVER)

I thought I just put it out here for people who run in the same thing I did.

like image 186
Wouter Avatar answered Sep 21 '22 23:09

Wouter


@Rollback(false) isn't always sufficient, it only means the transaction won't be rolled back at the end of test. But it still runs the test in a transaction, which sometimes lead to conflicts with other running transactions.

As Spring suggest, you have two options:

  1. Split the test class into two, the transactional tests can be a in test class annotated with @Transactional, while the non-transactional test in a test class without transactional annotation.
  2. Use method annotations instead of class annotation, annotate each transaction test with @Transactional, but remove it from the class scope

Quoting Spring documentation:

As of Spring 3.0, @NotTransactional is deprecated in favor of moving the non-transactional test method to a separate (non-transactional) test class or to a @BeforeTransaction or @AfterTransaction method. As an alternative to annotating an entire class with @Transactional, consider annotating individual methods with @Transactional; doing so allows a mix of transactional and non-transactional methods in the same test class without the need for using @NotTransactional.

like image 32
LiorH Avatar answered Sep 17 '22 23:09

LiorH