spring-projects / spring-projects/spring-framework

TestContext framework should support one AspectJ instance per ApplicationContext [SPR-6353]

Open
#11,019 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: core in: test type: enhancement
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

John Wu opened SPR-6353 and commented

The Symptom

  • Each test passes when running individually;
  • A few @Transactional tests may fail when running in a test suite. The failure may occur on any @Transactional test class, depending on the nondeterministic runtime tests sequence. In fact, it's quite difficult to reproduce before knowing the root cause.

Steps to Reproduce

  • Using Spring 2.5.6 or 3.0.0.RC1, JUnit 4;
  • Create a SimpleDbOpService (may or may not annotated with @Transactional), add a method to insert a record into DB based on the input parameters;
  • Create a SimpleDbOpATest:
@ContextConfiguration({"base.xml", "A.xml"})
  • Create a SimpleDbOpBTest:
@ContextConfiguration({"base.xml", "B.xml"})
  • Create a SimpleDbOpCTest:
@ContextConfiguration({"base.xml", "A.xml"})
  • Each test is annotated with @Transactional, calling the SimpleDbOpService and verifying the DB operation results at the end of test method;
  • <tx:annotation-driven mode="aspectj"/> in base.xml, also add "transactionManager" definition in
  • Create a test suite class as the following:
    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    
    @RunWith(Suite.class)
    @Suite.SuiteClasses({
      SimpleDbOpATest.class,
      SimpleDbOpBTest.class,
      SimpleDbOpCTest.class
    })
    public class Debug {
    
    }
  • The tests in SimpleDbOpCTest will fail.

Root Cause

In the Test Framework, it creates one instance of ApplicationContext for each "Set of context locations" and caches (and switches) the ApplicationContext instances by "context locations". Among all those ApplicationContext instances, the instance of AnnotationTransactionAspect is shared. That is, during the test suite running, there will be only one instance of AnnotationTransactionAspect, no matter how many ApplicationContext instances created.

A reference to BeanFactory (in spring 3.0.0.RC) or transactionManager (in spring 2.5.6) will be injected into AnnotationTransactionAspect (derived from TransactionAspectSupport) while the ApplicationContext being loaded.

In the example above, test A and C have the exactly same context locations, and they will share the same application context instance when running in a test suite. So, when running tests A, B, and C in a suite and in that order, the application context instance switches from A to B to A. However, the transactionManager instance (retrieved from an instance of AnnotationTransactionAspect) will be A, B, and B (should be A though), because there is only one instance of AnnotationTransactionAspect per class loader. In turn, that causes the operations in the C.testXxx() be split in to two transactionManager instances, one from AnnotationTransactionAspect and the other from ApplicationContext. Therefore, the DB result verification fails.

Proposed Solution

To create one Aspect instance per ApplicationContext, not per class loader. Not sure if that's achievable though.

Further Resources

Related Issues

  • #11897
  • #17123
  • #10789
  • #12619
  • #24794
  • #30229

Affects: 2.5.6, 3.0.5

Reference URL: http://forum.springsource.org/showthread.php?t=79949

5 votes, 7 watchers

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the TestContext framework's ApplicationContext caching and the AnnotationTransactionAspect lifecycle described in the issue. Reproduce the suite using SimpleDbOpATest, SimpleDbOpBTest, and SimpleDbOpCTest with the listed context configurations. Done means each ApplicationContext uses its own aspect instance and the C tests pass consistently when the suite runs.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
testing
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.