Skip to content

Introduce declarative customization of ApplicationContext before refresh in the TestContext framework [SPR-12603] #17204

@spring-projects-issues

Description

@spring-projects-issues

Josiah Haswell opened SPR-12603 and commented

It would be very nice for creating custom test annotations if we could get access to the GenericApplicationContext before it's loaded.

For instance:

I'm creating Cassandra and Datomic unit-testing support. I would like to generate schemata and import data before a test class is run, then clean up after a test is finished. Consider the following scenario:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@CassandraTest(
        configurationFile = "cassandra.yaml",
        timeout = 3600,
        port = 9143,
        host = "localhost",
        clusterName = "cluster"
)
public class CassandraPersistenceTestCase {

    @Configuration
    static class Config {
        // Cassandra configuration ...
    }

    @Autowired
    Cluster cluster;

    // test methods ...

}

In this scenario, I would like to use the annotation @CassandraTest on CassandraPersistenceTestCase to:

  1. Set up an embedded Cassandra instance
  2. Access the application context to register a Cluster configured from the annotation so that I may inject it into the test case.

If I use the TestExecutionListener APIs, then I have access to the PersistenceTestCase class, but only after the ApplicationContext has been refreshed.

If I use the ApplicationContextInitializer APIs, then I can access the ApplicationContext before it has been refreshed, but I cannot easily access the class annotated by CassandraTest.

I could implement all of this very easily if I could only get access to a subclass of the AbstractGenericContextLoader (specifically the customizeContext method), but everything in the call chain is package-local. I could even work around this if TestContextManager were an interface or an abstract superclass, but it isn't.

My proposal would be to introduce the following classes:

@Retention(RetentionPolicy.RUNTIME)
public @interface ContextDecorators {

    Class<? extends ContextDecorator>[] value() default {};
}
interface ContextDecorator {

    void decorate(TestContext context);
}

Then, in SpringJUnit4ClassRunner, check to see if that annotation exists on the test class. If it does, route it to an implementation of customizeContext() in AbstractGenericContextLoader that applies each ContextDecorator to that context.

This would be minimally invasive and not change the existing behavior at all if the annotation is omitted.

I will submit a pull request along these lines if no one has any objections, or if no superior alternatives are available.


Affects: 3.2 GA

Issue Links:

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions