<p dir="auto"><strong><a href="https://jira.spring.io/secure/ViewProfile.jspa?name=grzegorzborkowski" rel="nofollow">Grzegorz Borkowski</a></strong> opened <strong><a href="https://jira.spring.io/browse/SPR-7238?redirect=false" rel="nofollow">SPR-7238</a></strong> and commented</p>
<p dir="auto">I run unit tests using Spring integration testing tools, that is, marking test classes with <code class="notranslate">@ContextConfiguration</code>(locations = {...}) , which implies that Spring uses the same context for all test having the same context location configuration. In the tests, I call some transactional service. Transactions are weaved during compile time with AspectJ.<br>
The problem is following: as long as there is only one Spring context created during tests (all test classes using the some context location configuration, so there is only one context created), everything runs smoothly. But when one test uses different context configuration, and there are two contexts created (which should be independent from each other), transactions don't get started, and I got exception "no transaction in progress...".<br>
It looks like two contexts that should be independent, actually have some impact on each other. More precisely, it works this way: tests methods based on first spring contexts pass, then test methods using second context are run, and they pass, but then another test methods using first spring context are run and they fail with "No transaction" exception. So it look like running second context spoils the first one.<br>
This is serious problem for us, which makes running tests very difficult. JUnit doesn't let us decide on the order in which test methods are run, which makes this really problematic.</p>
<p dir="auto">I attach simple test case as maven project, run the test and see that they fail (if they are run in order: test 1, 2, 3). If you change the second test so that is uses the same context configuration like tests 1 and 3, everything works fine. But it test 2 uses different configuration, test 3 fails.</p>
<hr>
<p dir="auto"><strong>Affects:</strong> 3.0.2</p>
<p dir="auto"><strong>Reference URL:</strong> <a href="http://forum.springsource.org/showthread.php?p=301948#post301948" rel="nofollow">http://forum.springsource.org/showthread.php?p=301948#post301948</a></p>
<p dir="auto"><strong>Attachments:</strong></p>
<ul dir="auto">
<li><a href="https://jira.spring.io/secure/attachment/16596/springtestcase.zip" rel="nofollow">springtestcase.zip</a> (<em>17.86 kB</em>)</li>
</ul>
<p dir="auto"><strong>Issue Links:</strong></p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398099177" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/11019" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/11019/hovercard" href="https://github.com/spring-projects/spring-framework/issues/11019">#11019</a> TestContext framework should support one AspectJ instance per ApplicationContext (<em><strong>"duplicates"</strong></em>)</li>
</ul>
<p dir="auto">1 votes, 3 watchers</p>
<p dir="auto"><strong><a href="https://jira.spring.io/secure/ViewProfile.jspa?name=phantom_john" rel="nofollow">John Wu</a></strong> opened <strong><a href="https://jira.spring.io/browse/SPR-6353?redirect=false" rel="nofollow">SPR-6353</a></strong> and commented</p>
<h2 dir="auto">The Symptom</h2>
<ul dir="auto">
<li>Each test passes when running individually;</li>
<li>A few <code class="notranslate">@Transactional</code> tests may fail when running in a test suite. The failure may occur on any <code class="notranslate">@Transactional</code> test class, depending on the nondeterministic runtime tests sequence. In fact, it's quite difficult to reproduce before knowing the root cause.</li>
</ul>
<hr>
<h2 dir="auto">Steps to Reproduce</h2>
<ul dir="auto">
<li>Using Spring 2.5.6 or 3.0.0.RC1, JUnit 4;</li>
<li>Create a <code class="notranslate">SimpleDbOpService</code> (may or may not annotated with <code class="notranslate">@Transactional</code>), add a method to insert a record into DB based on the input parameters;</li>
<li>Create a SimpleDbOpATest:</li>
</ul>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@ContextConfiguration({&quot;base.xml&quot;, &quot;A.xml&quot;})"><pre class="notranslate"><span class="pl-c1">@</span><span class="pl-c1">ContextConfiguration</span>({<span class="pl-s">"base.xml"</span>, <span class="pl-s">"A.xml"</span>})</pre></div>
<ul dir="auto">
<li>Create a SimpleDbOpBTest:</li>
</ul>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@ContextConfiguration({&quot;base.xml&quot;, &quot;B.xml&quot;})"><pre class="notranslate"><span class="pl-c1">@</span><span class="pl-c1">ContextConfiguration</span>({<span class="pl-s">"base.xml"</span>, <span class="pl-s">"B.xml"</span>})</pre></div>
<ul dir="auto">
<li>Create a SimpleDbOpCTest:</li>
</ul>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@ContextConfiguration({&quot;base.xml&quot;, &quot;A.xml&quot;})"><pre class="notranslate"><span class="pl-c1">@</span><span class="pl-c1">ContextConfiguration</span>({<span class="pl-s">"base.xml"</span>, <span class="pl-s">"A.xml"</span>})</pre></div>
<ul dir="auto">
<li>Each test is annotated with <code class="notranslate">@Transactional</code>, calling the <code class="notranslate">SimpleDbOpService</code> and verifying the DB operation results at the end of test method;</li>
<li><code class="notranslate">&lt;tx:annotation-driven mode="aspectj"/&gt;</code> in <code class="notranslate">base.xml</code>, also add "transactionManager" definition in</li>
<li>Create a test suite class as the following:</li>
</ul>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    
    @RunWith(Suite.class)
    @Suite.SuiteClasses({
      SimpleDbOpATest.class,
      SimpleDbOpBTest.class,
      SimpleDbOpCTest.class
    })
    public class Debug {
    
    }"><pre class="notranslate">    <span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">junit</span>.<span class="pl-s1">runner</span>.<span class="pl-s1">RunWith</span>;
    <span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">junit</span>.<span class="pl-s1">runners</span>.<span class="pl-s1">Suite</span>;
    
    <span class="pl-c1">@</span><span class="pl-c1">RunWith</span>(<span class="pl-smi">Suite</span>.<span class="pl-k">class</span>)
    <span class="pl-c1">@</span><span class="pl-smi">Suite</span>.<span class="pl-s1">SuiteClasses</span>({
      <span class="pl-smi">SimpleDbOpATest</span>.<span class="pl-k">class</span>,
      <span class="pl-smi">SimpleDbOpBTest</span>.<span class="pl-k">class</span>,
      <span class="pl-smi">SimpleDbOpCTest</span>.<span class="pl-k">class</span>
    })
    <span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Debug</span> {
    
    }</pre></div>
<ul dir="auto">
<li>The tests in <code class="notranslate">SimpleDbOpCTest</code> will fail.</li>
</ul>
<hr>
<h2 dir="auto">Root Cause</h2>
<p dir="auto">In the Test Framework, it creates one instance of <code class="notranslate">ApplicationContext</code> for each "Set of context locations" and caches (and switches) the ApplicationContext instances by "context locations". Among all those <code class="notranslate">ApplicationContext</code> instances, the instance of <code class="notranslate">AnnotationTransactionAspect</code> is shared. That is, during the test suite running, there will be only one instance of <code class="notranslate">AnnotationTransactionAspect</code>, no matter how many <code class="notranslate">ApplicationContext</code> instances created.</p>
<p dir="auto">A reference to <code class="notranslate">BeanFactory</code> (in spring 3.0.0.RC) or <code class="notranslate">transactionManager</code> (in spring 2.5.6) will be injected into <code class="notranslate">AnnotationTransactionAspect</code> (derived from <code class="notranslate">TransactionAspectSupport</code>) while the <code class="notranslate">ApplicationContext</code> being loaded.</p>
<p dir="auto">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 <code class="notranslate">transactionManager</code> instance (retrieved from an instance of <code class="notranslate">AnnotationTransactionAspect</code>) will be A, B, and B (<strong>should be A though</strong>), because there is only one instance of <code class="notranslate">AnnotationTransactionAspect</code> per class loader. In turn, that causes the operations in the <code class="notranslate">C.testXxx()</code> be split in to two <code class="notranslate">transactionManager</code> instances, one from <code class="notranslate">AnnotationTransactionAspect</code> and the other from <code class="notranslate">ApplicationContext</code>. Therefore, the DB result verification fails.</p>
<h2 dir="auto">Proposed Solution</h2>
<p dir="auto">To create one Aspect instance per <code class="notranslate">ApplicationContext</code>, not per class loader. Not sure if that's achievable though.</p>
<h2 dir="auto">Further Resources</h2>
<ul dir="auto">
<li><a href="http://www.javacodegeeks.com/2014/04/spring-test-context-caching-aspectj-transactional-ehcache-pain.html" rel="nofollow">Spring Test Context Caching + AspectJ @Transactional + Ehcache pain</a> blog by Java Code Geeks</li>
</ul>
<h2 dir="auto">Related Issues</h2>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398105419" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/11897" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/11897/hovercard" href="https://github.com/spring-projects/spring-framework/issues/11897">#11897</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398174513" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/17123" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/17123/hovercard" href="https://github.com/spring-projects/spring-framework/issues/17123">#17123</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398097538" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/10789" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/10789/hovercard" href="https://github.com/spring-projects/spring-framework/issues/10789">#10789</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="398110169" data-permission-text="Title is private" data-url="https://github.com/spring-projects/spring-framework/issues/12619" data-hovercard-type="issue" data-hovercard-url="/spring-projects/spring-framework/issues/12619/hovercard" href="https://github.com/spring-projects/spring-framework/issues/12619">#12619</a></li>
</ul>
<hr>
<p dir="auto"><strong>Affects:</strong> 2.5.6, 3.0.5</p>
<p dir="auto"><strong>Reference URL:</strong> <a href="http://forum.springsource.org/showthread.php?t=79949" rel="nofollow">http://forum.springsource.org/showthread.php?t=79949</a></p>
<p dir="auto">5 votes, 7 watchers</p>