Feature Files
- The Gherkin feature files should be treated like software & managed with great care
- In doing so, not only will the framework be more concise & maintainable, but the BDD feature files essentially will write the framework themselves.
- Shared Step Definition files can act as reusable macros, making scenarios shorter while reducing the size of the framework and time to maintain them.
- Come up with a standard language and syntax for ALL feature files
- Create templates in Excel that have available test steps to choose from
- this will significantly reduce the amount of coding required for each scenario through REUSE
- and thereby reduce the time it takes to automate them
- and thereby avoid duplication of code & the cost of maintaining it
Step Definition Files
- Since collisions occur with duplicate method names across Definition Files, managing Step Definitions is critical to a healthy test ecosystem.
- simply creating arbitrary test steps in the feature file will result in utter chaos with BOTH feature file errors with duplicate step definitions AND with maintaining redundant Step Definitions that perform the same steps.
- Create subfolders with Definition Macros
- methods in the macros can reference other methods
- Since Drupal pages are templates comprised of 'blocks,
- it makes sense to model subfolders as drupal blocks
- Step Definitions would then be prefixed with the 'block name' and a '-'
- this prefix will also prevent step definition name collisions
- Using Excel to manage Step Definition string creation can facilitate consistent Step Definitions in the feature file
- and can also serve as a guide to know what dev work is required to support the feature
- and will allow the BDD feature author to simply pick from a library of functions to construct the scenario
- and will self-document the test architecture & supporting framework
Test Runner Files
- Add ALL the attributes to the runners
- this will avoid ambiguity when something isn't working
- Also will self-document the available options
Example Mock Up
- This feature file uses Test Steps from different StepDef files - in DIFFERENT subfolders under the *.StepDefs package
- The following two Test Steps have definitions in the StepDef: [ com.cs.cmsauto.bdd.StepDefs.MenuAdminLoginDefs.java ]
- Given user is already on Login Page
- Then close the browser
- The others use StepDefinitions from: [ com.cs.cmsauto.bdd.StepDefs.shared.menu_admin.DoNothingStepDefs.java ]
com.uc.test.cmsauto.bdd.features
Feature: Do Absolutely Nothing Scenario: So When Nothing is Done, Nothing Happens Given user is already on Login Page Given user is doing nothing When user still does nothing Then nothing happens Then close the browser
com.uc.test.cmsauto.bdd.runners
package com.cs.cmsauto.bdd.Runners; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class) @CucumberOptions( features= "src/test/java/com/cs/cmsauto/bdd/Features/donothing.feature" ,glue= {"com.cs.cmsauto.bdd.StepDefs"} ,format= {"pretty","html:test-output", "json:json-output/cucumber.json","junit:junit-xml-output/cucumber.xml"} ,monochrome = true ,strict = true //true = fail test suite if ANY test step not defined ,dryRun = true //true = check feature-definition-runner setup is valid... NO test logic executed ) public class DoNothingRunner { }
com.uc.test.cmsauto.bdd.stepdefs
- com.cs.cmsauto.bdd
- StepDefs
- CmsAutoDefinition.java - com.cs.cmsauto.bdd.StepDefs
- MenuAdminLoginDefs.java - com.cs.cmsauto.bdd.StepDefs
- shared
- menu_admin
- DoNothingStepDefs.java - com.cs.cmsauto.bdd.StepDefs.shared.menu_admin
- menu_admin
- StepDefs
CmsAutoDefinition.java - com.cs.cmsauto.bdd.StepDefs
package com.cs.cmsauto.bdd.StepDefs; import org.junit.After; import org.junit.Assert; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.interactions.Actions; import cucumber.api.java.en.And; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; public class CmsAutoDefinition { /* * * in order to use multiple StepDef files for Cucumber, * the webdriver must be instantiated globally OR * webdriver must be passed to called methods, etc * using POM will fix this & this issue is arising because this * is just a mockup for bdd analysis * */ private WebDriver driver; private WebElement el; String OS = "WINDOWS"; //String OS = "LINUX"; @Then("^title of the home page is Home Page$") public void title_of_the_home_page_is_Home_Page(){ String title = driver.getTitle(); Assert.assertEquals("HomePage", title); } @Then("^user moves to new contact page$") public void user_moves_to_new_contact_page() throws Throwable { el = driver.findElement(By.xpath("//frame[@name='mainpanel']")); driver.switchTo().frame(el); //mouse over the menu item Actions action = new Actions(driver); //new action // findElement.... build action to MOVE to element.... action.moveToElement(driver.findElement(By.xpath("//a[contains(.,'Contacts')]"))).build().perform(); // THEN click action.moveToElement(driver.findElement(By.xpath("//a[contains(.,'New Contact')]"))).build().perform(); el = driver.findElement(By.xpath("//a[contains(.,'New Contact')]")); el.click(); } @Then("^user enters contact details for firstname \"([^\"]*)\" and lastname \"([^\"]*)\" and position \"([^\"]*)\"$") public void user_enters_contact_details_and_and(String firstname, String lastname, String position) throws Throwable { driver.findElement(By.id("first_name")).sendKeys(firstname); driver.findElement(By.id("surname")).sendKeys(lastname); driver.findElement(By.id("company_position")).sendKeys(position); driver.findElement(By.xpath("//input[@type='submit' and @value='Save']")).click(); // page will redirect, check tabs_header for the new username el = driver.findElement(By.xpath("//td[contains(.,\'" + firstname + "\') and @class='tabs_header']")); Assert.assertEquals(firstname + " " + lastname, el.getText()); } @Then("^user verify contact created$") public void user_verify_contact_created(){ el = driver.findElement(By.xpath("//td[contains(.,firstname)]")); String title = driver.getTitle(); Assert.assertEquals("ContactCreated", title); } }
MenuAdminLoginDefs.java - com.cs.cmsauto.bdd.StepDefs
package com.cs.cmsauto.bdd.StepDefs; import org.junit.Assert; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import cucumber.api.java.en.And; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; public class MenuAdminLoginDefs { private WebDriver driver; private WebElement el; String OS = "WINDOWS"; //String OS = "LINUX"; @Given("^user is already on Login Page$") public void user_is_already_on_Login_Page() throws Throwable { if (OS.equals("WINDOWS")) { System.setProperty("webdriver.chrome.driver", "src/test/resources/executables/chromedriver-2.39-win32/chromedriver.exe"); } else if (OS.equals("LINUX")) { System.setProperty("webdriver.chrome.driver", "res/chromedriver/chromedriver-v2.39_linux64"); } driver = new ChromeDriver(); driver.get("https://unityconstruct.org/uc/"); } @When("^title of login page is PageTitle$") public void title_of_login_page_is_Free_CRM() throws Throwable { String title = driver.getTitle(); System.out.println(title); Assert.assertEquals("Home | UnityConstruct", title); } @Then("^user clicks on login link$") public void user_clicks_on_login_link() { driver.findElement(By.xpath("//a[contains(.,'Log in')]")).click(); } @Then("^user enters username \"([^\"]*)\" and password \"([^\"]*)\"$") public void user_enters_username_and_password(String username, String password) throws Throwable { driver.findElement(By.xpath("//input[@id='edit-name']")).sendKeys(username); driver.findElement(By.xpath("//input[@id='edit-pass']")).sendKeys(password); } @Then("^user clicks on login button$") public void user_clicks_on_login_button() throws Throwable { //Xpath.click technique driver.findElement(By.xpath("//input[@id='edit-submit']")).click(); } @Then("^user is on home page$") public void user_is_on_home_page() throws Throwable { String title = driver.getTitle(); System.out.println(title); Assert.assertEquals("TestAccount | UnityConstruct", title); } @And("^close the browser$") public void close_the_browser() { driver.quit(); } }
DoNothingStepDefs.java - com.cs.cmsauto.bdd.StepDefs.shared.menu_admin
package com.cs.cmsauto.bdd.StepDefs.shared.menu_admin; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; public class DoNothingStepDefs { @Given("^user is doing nothing$") public void user_is_doing_nothing() { System.out.println("user is doing nothing"); } @When("^user still does nothing$") public void user_still_does_nothing() { System.out.println("user still does nothing"); } @Then("^nothing happens$") public void nothing_happens(){ System.out.println("nothing heppens"); } }
StepDefs Tree Example
- shared
- macros
- logins
- content_filters
- content_creation
- content_deletion
- searches
- navigation
- menu_main
- menu_admin
- menu_tools
- search_bar
- search_advanced
- pages
- admin
- performance
- clear_cache()
- aggregate_cssjss()
- extend
- addmodule()
- content_all
- publishFirstItem()
- unpublisthFirstItem()
- filterByTitle()
- content_types
- book
- books_disable()
- article
- taxonomy
- book
- people
- performance
- home
- home-navigation
- home-menu-footer
- ideas
- ideas-navigation
- ideas-menu-footer
- ideas-content-filter
- admin
- drush
- calls
- site
- siteInstall
- siteUpdate
- siteRevert
- siteRename
- siteBackup
- db
- dbSwap
- tableSwap
- dbInsert
- dbBackup
- themes
- core
- modules
- disbableModule()
- enableModule()
- calls
- shell
- drupal
- sites
- wipeSites()
- resetSettingsPhpToDefault()
- themes
- wipeThemes()
- addTheme()
- sites
- logs
- pushLogs()
- resetLogs()
- parseLogs()
- archiveLogs()
-
- drupal
- Log in to post comments