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.
For a Spring Boot Actuator application, some additional management endpoints are available. You can use: POST to /actuator/env to update the Environment and rebind @ConfigurationProperties and log levels. /actuator/refresh to re-load the boot strap context and refresh the @RefreshScope beans.
Class ContextRefreshedEvent Event raised when an ApplicationContext gets initialized or refreshed.
We can have multiple application contexts that share a parent-child relationship. A context hierarchy allows multiple child contexts to share beans which reside in the parent context. Each child context can override configuration inherited from the parent context.
ApplicationContext is a corner stone of a Spring Boot application. It represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata.
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 (via value
and profiles
attributes) and programmatic configuration (via the resolver
attribute) of the active profiles for tests, but only at the test class level (not at the method level). Another option is to implement an ApplicationContextInitializer
and configure that via @ContextConfiguration(initializers=...)
.
The only other way to affect the ApplicationContext
before it is refreshed is to implement a SmartContextLoader
or extend one of the provided classes and configure it via @ContextConfiguration(loader=...)
. For example, AbstractGenericContextLoader.customizeContext()
allows one to "customize the GenericApplicationContext
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)
There's a nice little hack to trigger a context refresh - to use org.springframework.cloud.context.refresh.ContextRefresher
.
I'm not 100% sure this method will suite you: it requires a spring-cloud-context
dependency. However, this may be added just as a test
dependency and not leak into production classpath.
To use this refresher you also need to import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration
configuration, which adds a RefreshScope
scope to your applicationContext
which is actually doing the job under the hood.
So, modify test as follows:
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;
// your other imports
@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"}, classes = RefreshAutoConfiguration.class)
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {
@Autowired
private ContextRefresher contextRefresher;
@Test
public void test() throws Exception {
// doSmth before
contextRefresher.refresh();
// context is refreshed - continue testing
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With