Reputation: 57
I'm trying to use picocontainer for DI but still getting my shared object instantiated several times instead of being automatically managed as a singleton. Here's an example to illustrate. Classes ASteps and BSteps receive a SharedObject instance through their constructors. I expected it to be managed as a singleton by picocontainer: instantiated only once, as per the Cucumber docs. Instead, I see it gets instantiated once for ASteps and once for BSteps:
Running my.domain.CucumberRunTest
INFO [main] (CucumberHooks.java:15) - Executing before()
INFO [main] (SharedObject.java:11) - SharedObject - instantiated
INFO [main] (ASteps.java:21) - Executing a_step_one()
INFO [main] (ASteps.java:26) - Executing a_step_two()
INFO [main] (ASteps.java:31) - Executing a_step_three()
INFO [main] (CucumberHooks.java:20) - Executing after()
INFO [main] (CucumberHooks.java:15) - Executing before()
INFO [main] (SharedObject.java:11) - SharedObject - instantiated
INFO [main] (BSteps.java:23) - Executing b_step_one()
INFO [main] (BSteps.java:28) - Executing b_step_two()
INFO [main] (BSteps.java:33) - Executing b_step_three()
INFO [main] (CucumberHooks.java:20) - Executing after()
What am I doing wrong? Here is the code:
package my.domain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class ASteps {
final Logger log = LoggerFactory.getLogger(getClass());
SharedObject sharedObject;
public ASteps(SharedObject sharedObject) {
this.sharedObject = sharedObject;
}
@Given("^A step one$")
public void a_step_one() {
log.info("Executing a_step_one()");
}
@When("^A step two$")
public void a_step_two() {
log.info("Executing a_step_two()");
}
@Then("^A step three$")
public void a_step_three() {
log.info("Executing a_step_three()");
}
}
************************
package my.domain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class BSteps {
final Logger log = LoggerFactory.getLogger(getClass());
SharedObject sharedObject;
public BSteps(SharedObject sharedObject) {
this.sharedObject = sharedObject;
}
@Given("^B step one$")
public void b_step_one() {
log.info("Executing b_step_one()");
}
@When("^B step two$")
public void b_step_two() {
log.info("Executing b_step_two()");
}
@Then("^B step three$")
public void b_step_three() {
log.info("Executing b_step_three()");
}
}
************************
package my.domain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cucumber.api.java.After;
import cucumber.api.java.Before;
public class CucumberHooks {
final Logger log = LoggerFactory.getLogger(getClass());
@Before
public void before() {
log.info("Executing before()");
}
@After
public void after() {
log.info("Executing after()");
}
}
*********************
package my.domain;
import org.junit.runner.RunWith;
import cucumber.api.junit.Cucumber;
@RunWith(Cucumber.class)
public class CucumberRunTest {
}
**********************
package my.domain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SharedObject {
final Logger log = LoggerFactory.getLogger(getClass());
public SharedObject() {
log.info("SharedObject - instantiated");
}
}
Upvotes: 1
Views: 5157
Reputation: 517
I hope it's not too late to answer your question.
Actually, you can have what you want. I saw that you also want to have a single instance of your browser. You have to use static objects in order to do that. I created a little class to avoid the Open/close of the driver between each tests. It is managed by picocontainer. In your stepDefinition classes, you have to implement the "same" constructor.
Here is a sample :
public class myStepDefinition{
private Drivers context;
public myStepDefinition(Drivers context){
this.context = context;
// whatever you want to do
}
}
public class Drivers {
private static boolean initialized = false;
private static WebDriver driver;
@Before
public void initialize(){
if (!initialized){
initialized = true;
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.get("http://www.myurl.url");
}
}
public static WebDriver getDriver(){
return driver;
}
}
Keep in mind that you have to go back to you login page or your starting page after each test (passed or failed)
Regards,
Nicolas
Upvotes: 3
Reputation: 26743
The cache of the pico container is reset between scenarios, when the world is disposed of at the end of the scenario.
This is very much per design to avoid state leaking between scenarios and make them isolated so the order of the tests doesn't influence the results.
If you do wish to maintain state between scenario A and scenario B, you either need to handle SharedObject
yourself, outside of the pico container, or you can make the dependency between these two scenarios explicit – for example by using a Background.
Upvotes: 2