Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-6121

Dependency injection of @Configurable objects should work across test suites

    Details

    • Type: Improvement
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 2.5.6, 3.0.5
    • Fix Version/s: General Backlog
    • Component/s: Test
    • Labels:
      None

      Description

      Overview

      We have a large number of unit/integration tests that assert behavior within our system and rely upon injection of dependencies into configurable domain objects.

      These tests all work when executed individually; however, when executed within a suite (either through the IDE or Ant) certain tests fail as dependencies have not been injected into the @Configurable objects. We have also seen dependencies that were configured for test X being injected into test Y rather than the dependencies for test Y; but I have no test case for this.


      Steps to Reproduce

      I have created a set of three tests – tests 1 and 3 are basically identical. If these are executed in a suite the third test will fail as the dependency is not injected into the @Configurable object even though it is available to the test. This only occurs if test 2 is a Spring test.

      See attached zip file.


      Further Resources

        Issue Links

          Activity

          Hide
          mhunger Michael Hunger added a comment -

          Destroying the aspects only helps when you know all the aspects that are involved. For instance the @Transactional aspect also holds onto the old context, so whenever you for instance use that, an different transaction-manager could be used than the one you have configured in your current context.

          The root cause of this issue is that the context is cached and not reloaded when the third test runs. This should be also noted in different places in the documentation.

          Perhaps one should rather add those things as flags to @ContextConfiguration and not a separate @DirtiesContext, because the concern belongs there.

          Show
          mhunger Michael Hunger added a comment - Destroying the aspects only helps when you know all the aspects that are involved. For instance the @Transactional aspect also holds onto the old context, so whenever you for instance use that, an different transaction-manager could be used than the one you have configured in your current context. The root cause of this issue is that the context is cached and not reloaded when the third test runs. This should be also noted in different places in the documentation. Perhaps one should rather add those things as flags to @ContextConfiguration and not a separate @DirtiesContext, because the concern belongs there.
          Hide
          dkirrane DK added a comment - - edited

          I'm using Spring 3.1.1-RELEASE with spring-aspects and aspectjrt 1.7.1

          I tried both of the above workarounds to no avail. I tried both:

          @RunWith(MySpringJUnit4ClassRunner.class)
          @ContextConfiguration(locations = "classpath*:/MyFirtTest-context.xml")
          @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
          public class MyFirtTest {
              ...
          }

          @RunWith(MySpringJUnit4ClassRunner.class)
          @ContextConfiguration(locations = "classpath*:/MySecondTest-context.xml")
          @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
          public class MySecondTest {
              ...
          }

          If I add @Ignore to one of the tests everything works.
          However, if I include both tests then dependencies don't get injected with @Configurable.

          Show
          dkirrane DK added a comment - - edited I'm using Spring 3.1.1-RELEASE with spring-aspects and aspectjrt 1.7.1 I tried both of the above workarounds to no avail. I tried both: @RunWith(MySpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:/MyFirtTest-context.xml") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class MyFirtTest { ... } @RunWith(MySpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:/MySecondTest-context.xml") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class MySecondTest { ... } If I add @Ignore to one of the tests everything works. However, if I include both tests then dependencies don't get injected with @Configurable.
          Hide
          nealeu Neale Upstone added a comment - - edited

          I've just hit this one. It's a horrid pain debugging to know enough to come and find this bug report (and I suspect some people never get here).

          I agree with Michael Hunger that it's a ContextConfiguration concern. I think we should have an additional default TestExecutionListener, as shown in this snippet from what I've ended up with.

          @TestExecutionListeners({ServletTestExecutionListener.class, // Defaults plus new one
              DependencyInjectionTestExecutionListener.class,
              DirtiesContextTestExecutionListener.class,
              TransactionalTestExecutionListener.class,
              AbstractIntegrationTest.AspectBeanFactoryResettingListener.class})
          @Transactional
          public abstract class AbstractIntegrationTest {
           
              public static final class AspectBeanFactoryResettingListener extends AbstractTestExecutionListener {
                  @Override
                  public void prepareTestInstance(TestContext testContext) throws Exception {
           
                      DefaultListableBeanFactory factory = ((GenericApplicationContext) testContext.getApplicationContext())
                              .getDefaultListableBeanFactory();
                      AnnotationBeanConfigurerAspect.aspectOf().setBeanFactory(factory);
                      AnnotationTransactionAspect.aspectOf().setBeanFactory(factory);
                  }
              }
           
          ...
          }

          Naturally, there'd be a bit of work to deal with the scenarios when spring-aspects is not present, but I think a new default listener would save lots of people lots of pain (and I'd have been having my lunch an hour ago intead of rushing off now )

          Show
          nealeu Neale Upstone added a comment - - edited I've just hit this one. It's a horrid pain debugging to know enough to come and find this bug report (and I suspect some people never get here). I agree with Michael Hunger that it's a ContextConfiguration concern. I think we should have an additional default TestExecutionListener, as shown in this snippet from what I've ended up with. @TestExecutionListeners({ServletTestExecutionListener.class, // Defaults plus new one DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, AbstractIntegrationTest.AspectBeanFactoryResettingListener.class}) @Transactional public abstract class AbstractIntegrationTest {   public static final class AspectBeanFactoryResettingListener extends AbstractTestExecutionListener { @Override public void prepareTestInstance(TestContext testContext) throws Exception {   DefaultListableBeanFactory factory = ((GenericApplicationContext) testContext.getApplicationContext()) .getDefaultListableBeanFactory(); AnnotationBeanConfigurerAspect.aspectOf().setBeanFactory(factory); AnnotationTransactionAspect.aspectOf().setBeanFactory(factory); } }   ... } Naturally, there'd be a bit of work to deal with the scenarios when spring-aspects is not present, but I think a new default listener would save lots of people lots of pain (and I'd have been having my lunch an hour ago intead of rushing off now )
          Hide
          nealeu Neale Upstone added a comment -

          BTW. There's a related bug, SPR-5156, which may merit some consideration here.

          Show
          nealeu Neale Upstone added a comment - BTW. There's a related bug, SPR-5156 , which may merit some consideration here.
          Hide
          benze Eric B added a comment -

          I've just encountered this problem / bug myself. I'm amazed that after 6 years, it is still open! Is this so difficult to add to the SpringJUnit4ClassRunner class? Or are there a lot of other considerations that have to be considered?

          Show
          benze Eric B added a comment - I've just encountered this problem / bug myself. I'm amazed that after 6 years, it is still open! Is this so difficult to add to the SpringJUnit4ClassRunner class? Or are there a lot of other considerations that have to be considered?

            People

            • Assignee:
              sbrannen Sam Brannen
              Reporter:
              baronludwig Marc Ludwig
              Last updater:
              Juergen Hoeller
            • Votes:
              10 Vote for this issue
              Watchers:
              14 Start watching this issue

              Dates

              • Created:
                Updated:
                Days since last comment:
                1 year, 50 weeks ago