Spring Framework
  1. Spring Framework
  2. SPR-6184

Provide TestContext support for @Configuration classes

    Details

    • Last commented by a User:
      true

      Description

      Currently, JavaConfig integrates with the TestContext framework via its ContextLoader implementation, JavaConfigContextLoader:

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations="com.bank.TransferAppConfig",
                            loader=JavaConfigContextLoader.class)
      public class TransferServiceTests {
          // @Test methods ...
      }
      

      This integration works well enough but is not refactoring-friendly due to the requirement that @ContextConfiguration imposes that locations must be a String[]. It forces the fully-qualified class name to be expressed as a string, when it would clearly be superior to be able to pass it around by Class literal.

      Implementing this change would require a change to core, either by adding an attribute to @ContextConfiguration that takes a Class[] (not likely), or otherwise devising a way of proving a customized annotation (e.g., @JavaConfigContextConfiguration).

        Issue Links

          Activity

          Hide
          Eric Sirianni added a comment -

          I agree with Dave. The ideal flexibility would be to support wildcards with the semantics being that any class that matches that wildcard AND has an @Configuration annotation could be picked up. And further, to default the pattern to "$*" – this would satisfy the 'convention over configuration' but also give some naming flexibility to users.

          I can file another bug, but it seems like changing the default is a binary decision rather than an enhancement on top of this feature request. So why not just do that as part of the initial checkin of this feature?

          Show
          Eric Sirianni added a comment - I agree with Dave. The ideal flexibility would be to support wildcards with the semantics being that any class that matches that wildcard AND has an @Configuration annotation could be picked up. And further, to default the pattern to "$*" – this would satisfy the 'convention over configuration' but also give some naming flexibility to users. I can file another bug, but it seems like changing the default is a binary decision rather than an enhancement on top of this feature request. So why not just do that as part of the initial checkin of this feature?
          Hide
          Sam Brannen added a comment -

          Hi guys,

          Thanks for the quick feedback!

          I've modified AnnotationConfigContextLoader so that it now defines "$ContextConfiguration" as the resource suffix for the generated default @Configuration class name.

          Thus my previous examples are amended as follows:

          DefaultConfigClassesBaseTests.java
          @RunWith(SpringJUnit4ClassRunner.class)
          @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
          public class DefaultConfigClassesBaseTests {
          
          	@Configuration
          	static class ContextConfiguration {
          
          		@Bean
          		public Employee employee() {
          			Employee employee = new Employee();
          			employee.setName("John Smith");
          			employee.setAge(42);
          			employee.setCompany("Acme Widgets, Inc.");
          			return employee;
          		}
          	}
          
          
          	@Autowired
          	protected Employee employee;
          
          
          	@Test
          	public void verifyEmployeeSetFromBaseContextConfig() {
          		assertNotNull("The employee field should have been autowired.", this.employee);
          		assertEquals("John Smith", this.employee.getName());
          	}
          
          }
          
          ExplicitConfigClassesBaseTests.java
          @RunWith(SpringJUnit4ClassRunner.class)
          @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = DefaultConfigClassesBaseTests.ContextConfiguration.class)
          public class ExplicitConfigClassesBaseTests {
          
          	@Autowired
          	protected Employee employee;
          
          
          	@Test
          	public void verifyEmployeeSetFromBaseContextConfig() {
          		assertNotNull("The employee should have been autowired.", this.employee);
          		assertEquals("John Smith", this.employee.getName());
          	}
          
          }
          

          Notes:

          • DefaultConfigClassesBaseTests does not explicitly declare what @Configuration classes to use in @ContextConfiguration. Consequently a default configuration class name will be generated by appending "$ContextConfiguration" to the name of the test class, resulting in DefaultConfigClassesBaseTests$ContextConfiguration. This is a static class nested within the test class.
          • ExplicitConfigClassesBaseTests explicitly declares what @Configuration classes to use in @ContextConfiguration via the new classes attribute.
          • As with XML resource locations, the following are also supported with configuration classes via @ContextConfiguration:
            • configuration inheritance
            • merging local with inherited configuration
            • overriding inherited configuration (via the inheritLocations attribute)
          Show
          Sam Brannen added a comment - Hi guys, Thanks for the quick feedback! I've modified AnnotationConfigContextLoader so that it now defines "$ContextConfiguration" as the resource suffix for the generated default @Configuration class name. Thus my previous examples are amended as follows: DefaultConfigClassesBaseTests.java @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) public class DefaultConfigClassesBaseTests { @Configuration static class ContextConfiguration { @Bean public Employee employee() { Employee employee = new Employee(); employee.setName( "John Smith" ); employee.setAge(42); employee.setCompany( "Acme Widgets, Inc." ); return employee; } } @Autowired protected Employee employee; @Test public void verifyEmployeeSetFromBaseContextConfig() { assertNotNull( "The employee field should have been autowired." , this .employee); assertEquals( "John Smith" , this .employee.getName()); } } ExplicitConfigClassesBaseTests.java @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = DefaultConfigClassesBaseTests.ContextConfiguration.class) public class ExplicitConfigClassesBaseTests { @Autowired protected Employee employee; @Test public void verifyEmployeeSetFromBaseContextConfig() { assertNotNull( "The employee should have been autowired." , this .employee); assertEquals( "John Smith" , this .employee.getName()); } } Notes: DefaultConfigClassesBaseTests does not explicitly declare what @Configuration classes to use in @ContextConfiguration . Consequently a default configuration class name will be generated by appending "$ContextConfiguration" to the name of the test class, resulting in DefaultConfigClassesBaseTests$ContextConfiguration . This is a static class nested within the test class. ExplicitConfigClassesBaseTests explicitly declares what @Configuration classes to use in @ContextConfiguration via the new classes attribute. As with XML resource locations, the following are also supported with configuration classes via @ContextConfiguration : configuration inheritance merging local with inherited configuration overriding inherited configuration (via the inheritLocations attribute)
          Hide
          Sam Brannen added a comment -

          Eric,

          I agree with Dave. The ideal flexibility would be to support wildcards with the semantics being that any class that matches that wildcard AND has an @Configuration annotation could be picked up. And further, to default the pattern to "$*" – this would satisfy the 'convention over configuration' but also give some naming flexibility to users.

          I can file another bug, but it seems like changing the default is a binary decision rather than an enhancement on top of this feature request. So why not just do that as part of the initial checkin of this feature?

          What you describe would certainly be very flexible; however, that change will not make it into the soon-to-be-released Spring 3.1 M2.

          For 3.1 M2 we will stick with the current static "$ContextConfiguration" default suffix.

          So please do create a new JIRA issue to request the dynamic "$*" behavior you've suggested and select 3.1 RC1 as the fix version.

          Thanks,

          Sam

          Show
          Sam Brannen added a comment - Eric, I agree with Dave. The ideal flexibility would be to support wildcards with the semantics being that any class that matches that wildcard AND has an @Configuration annotation could be picked up. And further, to default the pattern to "$*" – this would satisfy the 'convention over configuration' but also give some naming flexibility to users. I can file another bug, but it seems like changing the default is a binary decision rather than an enhancement on top of this feature request. So why not just do that as part of the initial checkin of this feature? What you describe would certainly be very flexible; however, that change will not make it into the soon-to-be-released Spring 3.1 M2. For 3.1 M2 we will stick with the current static "$ContextConfiguration" default suffix. So please do create a new JIRA issue to request the dynamic "$*" behavior you've suggested and select 3.1 RC1 as the fix version. Thanks, Sam
          Hide
          Sam Brannen added a comment -

          Please note that, as a result of the changes implemented in conjunction with SPR-8395, AnnotationConfigContextLoader now generates a list of default configuration classes by finding all non-private, non-final, static, inner classes of the test class that are annotated with @Configuration. This lifts the restriction that such candidate default configuration classes be named ContextConfiguration. In other words, developers now have the freedom to name static inner @Configuration classes as they wish, and such classes will be automatically recognized as default configuration classes.

          Show
          Sam Brannen added a comment - Please note that, as a result of the changes implemented in conjunction with SPR-8395 , AnnotationConfigContextLoader now generates a list of default configuration classes by finding all non-private, non-final, static, inner classes of the test class that are annotated with @Configuration. This lifts the restriction that such candidate default configuration classes be named ContextConfiguration . In other words, developers now have the freedom to name static inner @Configuration classes as they wish, and such classes will be automatically recognized as default configuration classes.
          Hide
          Liam Knox added a comment -

          I think you need to be simple here.

          You already have a fantastic assumption of test contexts end with -context. You should close the loop here. It can be an inner class or outer, you then have a consistent framework

          Show
          Liam Knox added a comment - I think you need to be simple here. You already have a fantastic assumption of test contexts end with -context. You should close the loop here. It can be an inner class or outer, you then have a consistent framework

            People

            • Assignee:
              Sam Brannen
              Reporter:
              Chris Beams
              Last updater:
              Trevor Marshall
            • Votes:
              37 Vote for this issue
              Watchers:
              30 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                2 years, 44 weeks, 4 days ago