@Before and @Transactional

2019-03-25 07:29发布

问题:

I have

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(defaultRollback = true, transactionManager = "transactionManager")

   @Before
   @Transactional
   public void mySetup() {
      // insert some records in db
   }

   @After
   @Transactional
   public void myTeardown() {
      // delete some records
   }

   @Test
   @Transactional
   public void testMy() {
      // do stuff
   }

My question is: will mySetup, testMy and myTeardown all run within the same transaction? It seems like they should, but I'm getting some strange error which might suggest that they are stepping on each other.

回答1:

Yes, all three methods will run within the same transaction. See section TestContext Framework/Transaction management in the reference docs:

Any before methods (such as methods annotated with JUnit's @Before) and any after methods (such as methods annotated with JUnit's @After) are executed within a transaction

Thus the @Transactional annotation on mySetup() and myTeardown() is kind of redundant, or might be even considered misleading, as their transactionality is determined by the individual test method being currently executed.

This is because the beforeTestMethod() and afterTestMethod() callbacks of TransactionalTestExecutionListener (responsible for starting/completing the transaction) are executed before JUnit's @Before and after JUnit's @After methods, respectively.



回答2:

If you annotate your @Before and @After methods with @Transactional, they will not be run in a transaction. But if you use @Transactional for your test methods (methods that have @Test on them) or your test class as a whole, every test method will be run in different transaction and @Before and @After methods will also be run in the same transaction as for each @Test method. For more illustration, see these two code snippets:

@Transactional
public class MyTestClass {
    @Before
    public void beforeTest() {
        ...
    }

    @Test
    void testMethod1() {
        ...
    }

    @Test
    void testMethod2() {
        ...
    }

    @After
    public void afterTest() {
        ...
    }
}

The above code runs in exactly the same way as the below code:

public class MyTestClass {
    @Before
    public void beforeTest() {
        ...
    }

    @Test
    @Transactional
    void testMethod1() {
        ...
    }

    @Test
    @Transactional
    void testMethod2() {
        ...
    }

    @After
    public void afterTest() {
        ...
    }
}

In these two code snippets for each "testMethod1" and "testMethod2" methods there would be a different transaction. And also both "beforeMethod" and "afterMethod" methods would be run in each test method's transaction respectively.