Problem: How to share multiple variable /data between multiple step definitions along with state(if required) using Construction injection, dependent injection / Picocontainer.
Background: We had a very big step definition and it was getting difficult to manage it. So, we have decided to split Step definition into multiple small definitions using this new Automation base.
Stack: Selenium, Java , Cucumber,Junit, Picocontainer.
To achieve the above,we have looked for lot of suggestions on various websites and stackoverflow discussion,There are many suggestions like using Dependency Injection (Picocontainer), use Constructor Injection, spring etc.
After going through all those suggestions and page, we have found some grey areas(mentioned in problem above) that has not been answered anywhere in stackoverflow at one location/one answer/one page,So i am sharing this example to get more information that will help beginners and everyone. Structure of project files:
src
|->features
|----- login.feature
|----- product.feature
|----- payment.feature
|->java
|-->pagefactory
| |----- LoginPage.class
| |----- ProductPage.class
| |----- PaymentPage.class
|-->picoHelper
| |-----TestContext.class
|-->stepDefinition
| |-----LoginStepDef.class
| |-----SearchStepDef.class
| |-----ProductStepDef.class
| |-----PaymentStepDef.class
|-->helpers
| |-->wait
| |-----waitHelper.class
| |-->util
| |-----DriverFactoryManager.class
| |-----PageFactoryManager.class
By, this above testcontext constructor injection in step definition, we are able to split our big definitions and most of the test case are working fine. However, Issue is coming when we try to use a method that has some shared data between two step definition.
Feature file:
Feature: Verify Product Names and ID are being transferred to Payment Page
This feature will be used to validate Data
Scenario: Successful Login with Valid Credentials
Given User navigate to homepage of portal
When user enter valid credentials
Then user should be redirected to homepage
Scenario: To select the product
Given User is on product page
When User select product
And filterit via productsearch
Then user should be able to search this product
Scenario: Payment
Given User has selected product
When User click add to cart
Then System should display all related info for user to verify
TestContext looks like:
public class TestContext {
private DriverFactoryManager driverFactoryManager;
private PageObjectManager pageObjectManager;
public ScenarioContext scenarioContext;
public TestContext() {
driverFactoryManager = new DriverFactoryManager();
pageObjectManager = new PageObjectManager(driverFactoryManager.getDriver());
}
public DriverFactoryManager getDriverFactoryManager() {
return driverFactoryManager;
}
public PageObjectManager getPageObjectManager() {
return pageObjectManager;
}
}
Step definition: LoginStepDef
public class LoginStepDef {
LoginPage lp;
TestContext testContext;
private Logger log = LoggerHelper.getLogger(LoginStepDef.class);
public LoginStepDef(TestContext testContext) throws IOException {
lp = testContext.getPageObjectManager().getLoginPage();
}
//
methods to login to portal
Step Definition: ProductStepDefs
public class ProductStepDef {
private Logger log = LoggerHelper.getLogger(ProductStepDef.class);
TestContext testContext;
private LoginPage lp;
private ProductPage objPM;
String[] prodCodeName = new String[2];
String[] productDetails;
public ProductStepDef(TestContext testContext) {
this.testContext = testContext;
lp = testContext.getPageObjectManager().getLoginPage();
objPM = testContext.getPageObjectManager().getProductPage();
@Then("^user should be able to search this product$")
public void advancedSearchProduct {
objPM.advancedSearchProduct(searchKeyword);
prodCodeName = objPM.productDataProdCodeName();
log.info("product is: " + prodCodeName[0] + ". Its name is " + prodCodeName[1]); //expected 0 to show id and 1 to show name of product
productDetails = prodCodeName;
log.info("productDetails are : " + productDetails);
}
}
Step Definition: PaymentStepDefs
public class PaymentStepDef {
Logger log = LoggerHelper.getLogger(PaymentStepDef.class);
LoginPage lp;
Product objPM;
PaymentPage objPay;
String[] prodCodeName = new String[2];
String[] productDetails;
public PaymentStepDef(TestContext testContext) {
this.testContext = testContext;
lp = testContext.getPageObjectManager().getLoginPage();
objPM = testContext.getPageObjectManager().getProductPage();
objPay = testContext.getPageObjectManager().getPaymentPage();
@Then("^System should display all related info for user to verify$")
public void verifyExportResult() {
exportInfo = objPay.ExportResult(filter1, productDetails, numberOfItems );
THis Export results, take this productDetails to perform some action to compare with various version and then give perform some validation.
}
we want to access the product name and ID selected by user in 2nd scenario and validate in 3rd scenario. 2nd scenario is under ProductStepDefinition class and 3rd scenario of same feature file is in PaymentStepDefintion class.
Could someone please suggest a way to add a class inbetween this framework that can resolve issue of sharing multiple data of different datatype between multiple definitions
Cucumber was not meant to work this way. The outcome of one scenario should not be used as the basis for another scenario. Instead you need a
Given
step that emulates what the other scenario did.Scenario #3 should put a product in the system by specifying a name inside double quotes. The
When
step would take the user to the product details page and click the add to cart button. After that your existingThen
step can make the assertions.