I need to change the Spring profiles that are active in my applicationContext within a single method of my test class, and to do so I need to run one line of code before refreshing the contest because I am using a ProfileResolver. I have tried the following:
@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"})
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {
@Test
public void test() throws Exception {
codeToSetActiveProfiles(...);
((ConfigurableApplicationContext)this.applicationContext).refresh();
... tests here ...
codeToSetActiveProfiles(... back to prior profiles ...);
... ideally refresh/reload the context for future tests
}
}
But I get:
java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
DirtiesContext does not work for me because it is run AFTER class/method execution, not before, and I need to execute a line of code prior to running the refresh/reload anyway.
Any suggestions? I tried to have a look through the listeners/hooks that are being run, but I didn't see an obvious location to insert myself to achieve this behavior.
Not all application contextes support multiple
refresh
. According to javadoc forAbstractRefreshableApplicationContext
only subclasses of it or ofAbstractRefreshableWebApplicationContext
acceptrefresh
more than once ... andGenericApplicationContext
in not one of them.You should use another class for your
ApplicationContext
to support hot refresh.Edit :
As you are using
@ContextConfiguration
annotation, you should use a customContextLoader
orSmartContextLoader
implementation to force spring to use a less stupidApplicationContext
. But I never found a clean and neat way to to that. So when I need aXmlWebApplicationContext
in my test classes, I do not use@ContextConfiguration
but create and refresh my context by hand in a@Before
method or at the beginning of a test.I recognize this does not really answers your question, but you can see it as a workaround.
By design, programmatic refreshing of an
ApplicationContext
is not explicitly supported by the Spring TestContext Framework. Furthermore, it is not intended that a test method refresh a context.Thus I would recommend that you reassess your need for a refresh and consider alternatives like placing test methods that require a different set of active profiles in a dedicated test class.
In summary,
@ActiveProfiles
supports declarative configuration (viavalue
andprofiles
attributes) and programmatic configuration (via theresolver
attribute) of the active profiles for tests, but only at the test class level (not at the method level). Another option is to implement anApplicationContextInitializer
and configure that via@ContextConfiguration(initializers=...)
.The only other way to affect the
ApplicationContext
before it is refreshed is to implement aSmartContextLoader
or extend one of the provided classes and configure it via@ContextConfiguration(loader=...)
. For example,AbstractGenericContextLoader.customizeContext()
allows one to "customize theGenericApplicationContext
created by the loader after bean definitions have been loaded into the context but before the context is refreshed."Best regards,
Sam (author of the Spring TestContext Framework)