I'm struggling with Cucumber and Spring configuration. I'm writing selenium framework using Page Object Pattern, with BrowserFactory.
When I use @ComponentScan, @Component and @Autowire annotations everything works fine, but when I want to create a bit more complicated bean with @Bean annotation (BrowserFactory which registers few browser drivers) in @Configuration class it does not work, during debug I'm getting nulls on every single variable I'm trying to Autowire.
I'm using Spring 4.2.4, all cucumber dependencies in version 1.2.4.
Config:
@Configuration
public class AppConfig {
@Bean
@Scope("cucumber-glue")
public BrowserFactory browserFactory() {
BrowserFactory browserFactory = new BrowserFactory();
browserFactory.registerBrowser(new ChromeBrowser());
browserFactory.registerBrowser(new FirefoxBrowser());
return browserFactory;
}
@Bean(name = "loginPage")
@Scope("cucumber-glue")
public LoginPage loginPage() throws Exception {
return new LoginPage();
}
@Bean(name = "login")
@Scope("cucumber-glue")
public Login login() {
return new Login();
}
}
POP:
public class LoginPage extends Page {
public LoginPage() throws Exception {
super();
}
...
}
Page:
public class Page {
@Autowired
private BrowserFactory browserFactory;
public Page() throws Exception{
...
}
}
Login:
public class Login {
@Autowired
private LoginPage loginPage;
public Login(){}
...
}
Steps:
@ContextConfiguration(classes = {AppConfig.class})
public class LoginSteps {
@Autowired
Login login;
public LoginSteps(){
}
@Given("^an? (admin|user) logs in$")
public void adminLogsIn(Login.User user) throws Exception {
World.currentScenario().write("Logging in as " + user + "\n");
login.as(user);
}
}
Error:
cucumber.runtime.CucumberException: Error creating bean with name 'LoginSteps': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: Login LoginSteps.login; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'login': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private LoginPage Login.loginPage; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginPage' defined in AppConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [LoginPage]: Factory method 'loginPage' threw exception; nested exception is java.lang.NullPointerException
And now for the fun part... BrowserFactory in World class is properly Autowired!!
World:
public class World {
@Autowired
private BrowserFactory browserFactory;
...
}
So I'll answer my own question:)
Issue was that I was calling BrowserFactory inside of Page constructor. Looks like this bean was not yet created and was causing NPEs.
In order to fix that I:
Two more things to increase readability of Spring config: