I am working on a Spring Boot application using 1.5.8.RELEASE, which is configured and run via CLI. The parameters are used to configure the application to run in one or more different ways. One of the commands is to run all cucumber features and is called by using:
cucumber.api.cli.Main.main(cucumberArguments);
The current arguments passed include: featureFolder
, -g
, stepsPackage
, and a couple of cucumber-report configuration parameters.
I would like to be able to configure a few properties in my CucumberSteps*.java files via my application.properties file, or via profile-specific application.properties files, but the way I am running the features at the moment means that the Spring Boot context is not loaded.
My first attempt was:
@ConfigurationProperties
public class CucumberStepsFeature1 {
@Value("${my.property}")
private String myProperty;
@Given("...")
public void given() {
// fails below
assertNotNull(this.myProperty);
}
}
My second attempt at working around this issue was:
@ContextConfiguration(classes = MyMainApp.class)
@ConfigurationProperties
public class CucumberStepsFeature1 {
@Value("${my.property}")
private String myProperty;
@Given("...")
public void given() {
// fails below
assertNotNull(this.myProperty);
}
}
but I get an error message of
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Admin,name=SpringApplication
I tried following the steps listed here, but to no avail.
I'd appreciate any attempts to help, but I'll note now that due to company policy, what I share here will be very limited. I won't be able to copy or paste any real code snippets or logs.
Below is the cleanest way I could find to accomplish what I wanted:
Create a Config class to load in the Spring application properties that you need (application.properties and/or application-${PROFILE}.properties), such as below:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties
public class PropsConfig {
@Value("${my.property}")
private String myProperty;
//any other properties...
public String getMyProperty() {
return this.myProperty;
}
Create another class to act as a container for the Spring ApplicationContext. Make sure that this class is scanned by Spring by putting it in a subpackage of your main application class. See code below:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringApplicationContextContainer implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Autowired
public SpringApplicationContextContainer(ApplicationContext applicationContext) {
SpringApplicationContextContainer.applicationContext = applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringApplicationContextContainer.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return SpringApplicationContextContainer.applicationContext;
}
}
Finally, in your CucumberSteps class, or in any other non-Spring class, you can simply make a call to SpringApplicationContextContainer.getApplicationContext();
as below:
public class CucumberStepsFeature1 {
private final PropsConfig propsConfig;
public CucumberStepsFeature1() {
this.propsConfig = SpringApplicationContextContainer.getApplicationContext().getBean(PropsConfig.class);
}
@Given("...")
public void given() {
// passes below
assertNotNull(this.propsConfig);
}