192
serenity-bdd.info #SerenityBDD @Wakaleo Sustainable Test Automation with Serenity BDD and Screenplay

Sustainable Test Automation with Serenity BDD and Screenplay

Embed Size (px)

Citation preview

Page 1: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Sustainable Test Automationwith Serenity BDD and Screenplay

Page 2: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

John Ferguson SmartAuthor of ‘BDD in Action’ Lead Developer of Serenity BDDFounder of the Serenity Dojo

Page 3: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Page 4: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Page 5: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Want to follow along?

bit.ly/serentiy-planner

Page 6: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

We ❤ E2E

Page 7: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

We 💔 E2E(said no one ever)

Page 8: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Execution time: minutes → hours

Page 9: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Execution time: minutes → hours

Writing: hours → days

Page 10: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Execution time: minutes → hours

Writing: hours → days

Analysis and reporting: hours → days

Page 11: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Execution time: minutes → hours

Writing: hours → days

Analysis and reporting: hours → days

Maintenance: days → weeks

Page 12: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

The difference between scalable tests

and a world of pain is design.

Page 13: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Testing the Journey Planner

Page 14: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Page 15: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

When a commuter wants to travel from Waterloo to Canary Wharf around 9:00 AM they should be told about the 8:59 AM Jubilee Line train.

Page 16: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey Planner

Page 17: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo

Page 18: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo”

Page 19: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion

Page 20: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions

Page 21: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼

Page 22: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼ Press ↩

Page 23: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼ Press ↩

Page 24: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo serenity-bdd.info

Open the Journey PlannerChoose origin: Waterloo

Page 25: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary Wharf

Page 26: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary Wharf

Page 27: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM

Page 28: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM Click on the “change time” link

Page 29: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM Click on the “change time” link Click on the “Leaving” button

Page 30: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM Click on the “change time” link Click on the “Leaving” button Select “09:00”

Page 31: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM

Page 32: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection

Page 33: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection Click on the “Plan my journey”

Page 34: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection Click on the “Plan my journey” Wait for the results to load

Page 35: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection

Page 36: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selectionSee a Jubilee Line train at 08:59

Page 37: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

At a high level,it’s just 6 tasks

Page 38: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Scripting the flow

Page 39: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

private final By origin = By.id("InputFrom"); private final By originSuggestions = By.cssSelector(".tt-suggestions"); private final By destination = By.id("InputTo"); private final By destinationSuggestions = By.cssSelector(".tt-suggestions"); private final By changeTimeLink = By.partialLinkText("change time"); private final By leavingButton = By.cssSelector("label[for=departing]"); private final By timeSelector = By.id("Time"); private final By planMyJourneyButton = By.cssSelector("#plan-a-journey .plan-journey-button"); private final By journeyResults = By.cssSelector(".summary-results"); private final By fastestJourney = By.cssSelector(".publictransport-box span.time");

Page 40: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get("https://tfl.gov.uk/");

Page 41: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys("Waterloo");

Page 42: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys(“Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10);wait.until(visibilityOfElementLocated(originSuggestions));

Page 43: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys(“Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10);wait.until(visibilityOfElementLocated(originSuggestions));

browser.findElement(originSuggestions).sendKeys(ARROW_DOWN);browser.findElement(originSuggestions).sendKeys(ENTER);

Page 44: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys(“Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10);wait.until(visibilityOfElementLocated(originSuggestions));

browser.findElement(originSuggestions).sendKeys(ARROW_DOWN);browser.findElement(originSuggestions).sendKeys(ENTER);

browser.findElement(destination).sendKeys("Canary Wharf");

Page 45: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys(“Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10);wait.until(visibilityOfElementLocated(originSuggestions));

browser.findElement(originSuggestions).sendKeys(ARROW_DOWN);browser.findElement(originSuggestions).sendKeys(ENTER);

browser.findElement(destination).sendKeys("Canary Wharf”);wait.until(visibilityOfElementLocated(destinationSuggestions));browser.findElement(destinationSuggestions).sendKeys(ARROW_DOWN);browser.findElement(destinationSuggestions).sendKeys(ENTER);

Page 46: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

…browser.findElement(changeTimeLink).click();browser.findElement(leavingButton).click();new Select(browser.findElement(timeSelector)) .selectByVisibleText("09:00");

Page 47: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

…browser.findElement(changeTimeLink).click();browser.findElement(leavingButton).click();new Select(browser.findElement(timeSelector)) .selectByVisibleText(“09:00");

browser.findElement(planMyJourneyButton).click();

wait.until(visibilityOfElementLocated(journeyResults));

Page 48: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

…String fastestDepartureTime = startTimeOf(browser.findElement(fastestJourney).getText());

assertThat(fastestDepartureTime).isEqualTo("08:59");

Page 49: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

private final By origin = By.id("InputFrom"); private final By originSuggestions = By.cssSelector(".tt-suggestions"); private final By destination = By.id("InputTo"); private final By destinationSuggestions = By.cssSelector(".tt-suggestions"); private final By changeTimeLink = By.partialLinkText("change time"); private final By leavingButton = By.cssSelector("label[for=departing]"); private final By timeSelector = By.id("Time"); private final By planMyJourneyButton = By.cssSelector("#plan-a-journey .plan-journey-button"); private final By journeyResults = By.cssSelector(".summary-results"); private final By fastestJourney = By.cssSelector(".publictransport-box span.time");

private WebDriver browser;

@Before public void openBrowser() { browser = new FirefoxDriver(); }

@After public void closeBrowser() { browser.quit(); }

@Test public void planning_a_journey() {

browser.get("https://tfl.gov.uk/"); browser.findElement(origin).sendKeys("Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10); wait.until(visibilityOfElementLocated(originSuggestions));

browser.findElement(originSuggestions).sendKeys(ARROW_DOWN); browser.findElement(originSuggestions).sendKeys(ENTER);

browser.findElement(destination).sendKeys("Canary Wharf");

wait.until(visibilityOfElementLocated(destinationSuggestions)); browser.findElement(destinationSuggestions).sendKeys(ARROW_DOWN); browser.findElement(destinationSuggestions).sendKeys(ENTER);

browser.findElement(changeTimeLink).click(); browser.findElement(leavingButton).click();

new Select(browser.findElement(timeSelector)).selectByVisibleText("09:00");

browser.findElement(planMyJourneyButton).click();

wait.until(visibilityOfElementLocated(journeyResults));

String fastestDepartureTime = startTimeOf(browser.findElement(fastestJourney).getText());

6 tasks ?

Page 50: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

6 tasks buried in36 lines of noise

private final By origin = By.id("InputFrom"); private final By originSuggestions = By.cssSelector(".tt-suggestions"); private final By destination = By.id("InputTo"); private final By destinationSuggestions = By.cssSelector(".tt-suggestions"); private final By changeTimeLink = By.partialLinkText("change time"); private final By leavingButton = By.cssSelector("label[for=departing]"); private final By timeSelector = By.id("Time"); private final By planMyJourneyButton = By.cssSelector("#plan-a-journey .plan-journey-button"); private final By journeyResults = By.cssSelector(".summary-results"); private final By fastestJourney = By.cssSelector(".publictransport-box span.time");

private WebDriver browser;

@Before public void openBrowser() { browser = new FirefoxDriver(); }

@After public void closeBrowser() { browser.quit(); }

@Test public void planning_a_journey() {

browser.get("https://tfl.gov.uk/"); browser.findElement(origin).sendKeys("Waterloo");

WebDriverWait wait = new WebDriverWait(browser, 10); wait.until(visibilityOfElementLocated(originSuggestions));

browser.findElement(originSuggestions).sendKeys(ARROW_DOWN); browser.findElement(originSuggestions).sendKeys(ENTER);

browser.findElement(destination).sendKeys("Canary Wharf");

wait.until(visibilityOfElementLocated(destinationSuggestions)); browser.findElement(destinationSuggestions).sendKeys(ARROW_DOWN); browser.findElement(destinationSuggestions).sendKeys(ENTER);

browser.findElement(changeTimeLink).click(); browser.findElement(leavingButton).click();

new Select(browser.findElement(timeSelector)).selectByVisibleText("09:00");

browser.findElement(planMyJourneyButton).click();

wait.until(visibilityOfElementLocated(journeyResults));

String fastestDepartureTime = startTimeOf(browser.findElement(fastestJourney).getText());

Page 51: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo

serenity-bdd.info

If you have WebDriver APIs in your test methods, You’re Doing It Wrong!- Simon Stewart, creator of WebDriver

Page 52: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

A test system needs design

Page 53: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Page Objects to the rescue?

Page 54: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Page 55: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@DefaultUrl(“https://tfl.gov.uk")public class JourneyPlannerPage extends PageObject { // Locators // Actions}

Page 56: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@DefaultUrl(“https://tfl.gov.uk")public class JourneyPlannerPage extends PageObject { // Locators @FindBy(id = "InputFrom") private WebElementFacade origin;

@FindBy(className = "tt-suggestions") private WebElementFacade originSuggestions;

@FindBy(id = “InputTo") private WebElementFacade destination;

@FindBy(className = “tt-suggestions") private WebElementFacade destinationSuggestions;

@FindBy(partialLinkText = "change time”) private WebElementFacade changeTimeLink; …

Page 57: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@DefaultUrl(“https://tfl.gov.uk")public class JourneyPlannerPage extends PageObject { // Locators …

// Actions public void chooseOriginOf(String originValue) { origin.sendKeys(originValue); waitFor(visibilityOf(originSuggestions));

originSuggestions.sendKeys(Keys.ARROW_DOWN); originSuggestions.sendKeys(Keys.ENTER); }

public void chooseDestinationOf(String destinationValue) {…} public void confirmSelection() {…}}

Page 58: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest {

Page 59: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest { @Managed WebDriver driver;

Page 60: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest { @Managed WebDriver driver;

JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;

Page 61: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;

journeyPlanner.open(); journeyPlanner.chooseOriginOf(“Waterloo"); journeyPlanner.chooseDestinationOf("Canary Wharf”); journeyPlanner.chooseTimeOfDeparture(“09:00”); journeyPlanner.confirmSelection();

Page 62: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;

journeyPlanner.open(); journeyPlanner.chooseOriginOf(“Waterloo"); journeyPlanner.chooseDestinationOf("Canary Wharf”); journeyPlanner.chooseTimeOfDeparture(“09:00”); journeyPlanner.confirmSelection();

assertThat(journeyResults.getFastestJourneyDepartureTime()) .isEqualTo(“08:59");

Page 63: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest {

@Managed WebDriver driver;

JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;

@Test public void planning_a_journey() {

journeyPlanner.open();

journeyPlanner.chooseOriginOf("Waterloo"); journeyPlanner.chooseDestinationOf("Canary Wharf"); journeyPlanner.chooseTimeOfDeparture("09:00"); journeyPlanner.confirmSelection();

assertThat(journeyResults.getFastestJourneyDepartureTime()) .isEqualTo("08:59"); } }

not bad!

Page 64: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

not bad?

@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest {

@Managed WebDriver driver;

JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;

@Test public void planning_a_journey() {

journeyPlanner.open();

journeyPlanner.chooseOriginOf("Waterloo"); journeyPlanner.chooseDestinationOf("Canary Wharf"); journeyPlanner.chooseTimeOfDeparture("09:00"); journeyPlanner.confirmSelection();

assertThat(journeyResults.getFastestJourneyDepartureTime()) .isEqualTo("08:59"); } }

Page 65: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@DefaultUrl("https://tfl.gov.uk") public class JourneyPlannerPage extends PageObject {

@FindBy(id = "InputFrom") private WebElementFacade origin;

@FindBy(className = "tt-suggestions") private WebElementFacade originSuggestions;

@FindBy(id = "InputTo") private WebElementFacade destination;

@FindBy(className = "tt-suggestions") private WebElementFacade destinationSuggestions;

@FindBy(partialLinkText = "change time") private WebElementFacade changeTimeLink;

@FindBy(css = "label[for=departing]") private WebElementFacade leavingButton;

@FindBy(id = "Time") private WebElement timeSelector;

@FindBy(css = "#plan-a-journey .plan-journey-button") private WebElementFacade planMyJourneyButton;

@FindBy(className = "summary-results") private WebElementFacade journeyResults;

public void chooseOriginOf(String originValue) { origin.sendKeys(originValue);

waitFor(visibilityOf(originSuggestions));

originSuggestions.sendKeys(Keys.ARROW_DOWN); originSuggestions.sendKeys(Keys.ENTER); }

public void chooseDestinationOf(String destinationValue) { destination.sendKeys(destinationValue);

waitFor(visibilityOf(destinationSuggestions));

destinationSuggestions.sendKeys(Keys.ARROW_DOWN); destinationSuggestions.sendKeys(Keys.ENTER); }

public void chooseTimeOfDeparture(String timeOfDeparture) { changeTimeLink.click(); leavingButton.click();

selectFromDropdown(timeSelector, timeOfDeparture); }

public void confirmSelection() {

planMyJourneyButton.click();

waitFor(visibilityOf(journeyResults)); }

large classes

Page 66: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

large classesbloated methods

@DefaultUrl("https://tfl.gov.uk") public class JourneyPlannerPage extends PageObject {

@FindBy(id = "InputFrom") private WebElementFacade origin;

@FindBy(className = "tt-suggestions") private WebElementFacade originSuggestions;

@FindBy(id = "InputTo") private WebElementFacade destination;

@FindBy(className = "tt-suggestions") private WebElementFacade destinationSuggestions;

@FindBy(partialLinkText = "change time") private WebElementFacade changeTimeLink;

@FindBy(css = "label[for=departing]") private WebElementFacade leavingButton;

@FindBy(id = "Time") private WebElement timeSelector;

@FindBy(css = "#plan-a-journey .plan-journey-button") private WebElementFacade planMyJourneyButton;

@FindBy(className = "summary-results") private WebElementFacade journeyResults;

public void chooseOriginOf(String originValue) { origin.sendKeys(originValue);

waitFor(visibilityOf(originSuggestions));

originSuggestions.sendKeys(Keys.ARROW_DOWN); originSuggestions.sendKeys(Keys.ENTER); }

public void chooseDestinationOf(String destinationValue) { destination.sendKeys(destinationValue);

waitFor(visibilityOf(destinationSuggestions));

destinationSuggestions.sendKeys(Keys.ARROW_DOWN); destinationSuggestions.sendKeys(Keys.ENTER); }

public void chooseTimeOfDeparture(String timeOfDeparture) { changeTimeLink.click(); leavingButton.click();

selectFromDropdown(timeSelector, timeOfDeparture); }

public void confirmSelection() {

planMyJourneyButton.click();

waitFor(visibilityOf(journeyResults)); }

Page 67: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

large classesbloated methodsdifficult to compose

@DefaultUrl("https://tfl.gov.uk") public class JourneyPlannerPage extends PageObject {

@FindBy(id = "InputFrom") private WebElementFacade origin;

@FindBy(className = "tt-suggestions") private WebElementFacade originSuggestions;

@FindBy(id = "InputTo") private WebElementFacade destination;

@FindBy(className = "tt-suggestions") private WebElementFacade destinationSuggestions;

@FindBy(partialLinkText = "change time") private WebElementFacade changeTimeLink;

@FindBy(css = "label[for=departing]") private WebElementFacade leavingButton;

@FindBy(id = "Time") private WebElement timeSelector;

@FindBy(css = "#plan-a-journey .plan-journey-button") private WebElementFacade planMyJourneyButton;

@FindBy(className = "summary-results") private WebElementFacade journeyResults;

public void chooseOriginOf(String originValue) { origin.sendKeys(originValue);

waitFor(visibilityOf(originSuggestions));

originSuggestions.sendKeys(Keys.ARROW_DOWN); originSuggestions.sendKeys(Keys.ENTER); }

public void chooseDestinationOf(String destinationValue) { destination.sendKeys(destinationValue);

waitFor(visibilityOf(destinationSuggestions));

destinationSuggestions.sendKeys(Keys.ARROW_DOWN); destinationSuggestions.sendKeys(Keys.ENTER); }

public void chooseTimeOfDeparture(String timeOfDeparture) { changeTimeLink.click(); leavingButton.click();

selectFromDropdown(timeSelector, timeOfDeparture); }

public void confirmSelection() {

planMyJourneyButton.click();

waitFor(visibilityOf(journeyResults)); }

Page 68: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Four Software Engineering Principles can help you write more maintainable tests

Page 69: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

1) Separation of ConcernsHide complexity through layers of abstraction

Page 70: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

2) Single Responsibility PrincipleA class should have only one reason to change

Page 71: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

3) Open-Closed PrincipleGreen diffs

Page 72: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

4) Narrative coding styleExpress your intent

Page 73: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Serenity BDD andthe Screenplay Pattern

Page 74: Sustainable Test Automation with Serenity BDD and Screenplay

#SerenityBDD @Wakaleo

serenity-bdd.info

Your test framework should not model how your system behaves. It should model how your user behaves.

Page 75: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Page 76: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

GoalsWhat are you trying to achieve?

Page 77: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

GoalsWhat are you trying to achieve?

Tasks What do you need to do to achieve this goal?

Page 78: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

GoalsWhat are you trying to achieve?

Tasks What do you need to do to achieve this goal?

InteractionsWhat interactions with the

system do you need for each task?

Page 79: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Actor

Connor the commuter

Page 80: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Plan my journey

Actor Goals

Connor the commuter

Page 81: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Plan my journey

Actor Goals Tasks

Choose Destination

Choose Origin

Choose time of departure

Confirm selection

Connor the commuter

Page 82: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Plan my journey

Actor Goals Tasks Interactions

Press “Down”

Type “Waterloo”

Choose Destination

Choose Origin

Choose time of departure

Press “Enter”

Confirm selection

Connor the commuter

Page 83: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Say what you mean

Page 84: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Open the Journey Planner Choose origin of Waterloo Choose destination of Canary Wharf Choose time of departure: 09:00 Confirm selection See if the fastest train departs at 08:59

Page 85: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

OpenApplication.onTheJourneyPlannerPage(), ChooseOrigin.of("Waterloo"), ChooseDestination.of("Canary Wharf"), ChooseTimeOfDeparture.of("09:00"), Confirm.journeyDetails(), seeThat(TheFastest.departureTime(), is("08:59"))

Page 86: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Designing a task

Page 87: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

ChooseOrigin.of("Waterloo")

Page 88: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task { }

Page 89: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) {} }

Page 90: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( ); } }

Page 91: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN) ); } }

Page 92: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) ); } }

Page 93: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), ); } }

Page 94: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station; }

Page 95: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

}

Page 96: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

public static Performable of(String station) { return instrumented(ChooseOrigin.class, station); } }

Page 97: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Step("{0} selects origin station of #station") @Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

public static Performable of(String station) { return instrumented(ChooseOrigin.class, station); } }

Page 98: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Step("{0} selects origin station of #station") @Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

public static Performable of(String station) { return instrumented(ChooseOrigin.class, station); } }

How the step appears in the reports

Page 99: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Step("{0} selects origin station of #station") @Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

public static Performable of(String station) { return instrumented(ChooseOrigin.class, station); } }

The name of the actor

Page 100: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseOrigin implements Task {

@Step("{0} selects origin station of #station") @Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( Enter.theValue(station).into(JourneyPlanner.ORIGIN), WaitUntil.the(JourneyPlanner.ORIGIN_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.ORIGIN) ); }

private final String station;

public ChooseOrigin(String origin) { this.station = origin;}

public static Performable of(String station) { return instrumented(ChooseOrigin.class, station); } }

A member variable

Page 101: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Or…

Page 102: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", } }

Page 103: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", Enter.theValue(station).into(JourneyPlanner.DESTINATION), } }

Page 104: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", Enter.theValue(station).into(JourneyPlanner.DESTINATION), WaitUntil.the(JourneyPlanner.DESTINATION_SUGGESTIONS, isVisible()) } }

Page 105: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", Enter.theValue(station).into(JourneyPlanner.DESTINATION), WaitUntil.the(JourneyPlanner.DESTINATION_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), } }

Page 106: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", Enter.theValue(station).into(JourneyPlanner.DESTINATION), WaitUntil.the(JourneyPlanner.DESTINATION_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.DESTINATION)) } }

Page 107: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class ChooseDestination {

/** * Usage: ChooseDestination.of("Canary Wharf") */ public static Task of(String station) { return Task.where("{0} selects origin station of #station", Enter.theValue(station).into(JourneyPlanner.DESTINATION), WaitUntil.the(JourneyPlanner.DESTINATION_SUGGESTIONS, isVisible()) .forNoMoreThan(10).seconds(), PickFirstSuggestion.from(JourneyPlanner.DESTINATION)) .with(“station").of(station); } }

Page 108: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Interactions talk to the system

Page 109: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Most WebDriver interactions come bundled with Serenity Screenplay

Enter.theValue(station).into(JourneyPlanner.ORIGIN)

Click.on(JourneyPlanner.PLAN_MY_JOURNEY)

SelectFromOptions.byVisibleText(timeOfDeparture) .from(JourneyPlanner.SELECTED_DEPARTURE_TIME)

WaitUntil.the(JourneyResults.RESULTS_LIST, isVisible())

Scroll.to(JourneyResults.RESULTS_LIST)

Page 110: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Actors perform tasks

Page 111: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

import net.serenitybdd.screenplay.Actor;

Actor connie = Actor.named("Connie");

Page 112: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

import net.serenitybdd.screenplay.Actor;

Actor connie = Actor.named("Connie");

connie.attemptsTo( //…);

Page 113: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Actor connie = Actor.named("Connie");

connie.attemptsTo( OpenApplication.onTheJourneyPlannerPage(), ChooseOrigin.of("Waterloo"), ChooseDestination.of("Canary Wharf"), ChooseTimeOfDeparture.of(“09:00"), Confirm.journeyDetails()

Page 114: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Actors have abilities that enable interactions

with the system

Page 115: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@Managed WebDriver browser;

Actor connie = Actor.named("Connie"); connie.can(BrowseTheWeb.with(browser));

Page 116: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

But where did the Page Objects go?

Page 117: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class JourneyPlanner {

public static final Target ORIGIN = Target.the("Departure station") .locatedBy("#InputFrom");

public static final Target ORIGIN_SUGGESTIONS = Target.the("Origin Suggestions") .locatedBy("//*[input[@id='InputFrom']]/*[contains(@class, 'tt-dropdown-menu')]");

public static final Target DESTINATION = Target.the("Destination station") .locatedBy("#InputTo");

public static final Target DESTINATION_SUGGESTIONS = Target.the("Destination Suggestions") .locatedBy("//*[input[@id='InputTo']]/*[contains(@class, 'tt-dropdown-menu')]");

public static final Target CHANGE_TIME = Target.the("Change Time") .located(By.partialLinkText("change time"));

public static final Target LEAVING_BUTTON = Target.the("Leaving") .located(By.cssSelector("label[for=departing]"));

public static final Target SELECTED_DEPARTURE_TIME = Target.the("Departure Time") .located(By.id("Time"));

public static final Target SELECTED_DEPARTURE_DROPDOWN = Target.the("Departure Time") .located(By.cssSelector(".hours"));

public static final Target PLAN_MY_JOURNEY = Target.the("Plan my journey") .locatedBy("#plan-a-journey .plan-journey-button");;

}

Page 118: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Target.the("Departure station").locatedBy("#InputFrom");

Page 119: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Target.the("Departure station").locatedBy("#InputFrom");

How should this element be named in the reports?

Page 120: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Target.the("Departure station").locatedBy("#InputFrom");

How should we locate it?

Page 121: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

What about more complicated cases?

Page 122: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Target FILTER = Target.the(“filter") .locatedBy("//*[@class='filters']//a[.='{0}']");

This value will be provided

Page 123: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

theActor.attemptsTo(FilterItems.toShow(“Completed"));

Page 124: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class FilterItems implements Task {

private final String filter;

public <T extends Actor> void performAs(T theActor) { }

public static FilterItems toShow(String filter) { return instrumented(FilterItems.class, status); } public FilterItems(TodoStatusFilter filter) { this.filter = filter; } }

Page 125: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class FilterItems implements Task {

private final String filter;

public <T extends Actor> void performAs(T theActor) { theActor.attemptsTo( Click.on(TodoList.FILTER ); }

public static FilterItems toShow(String filter) { return instrumented(FilterItems.class, status); } public FilterItems(TodoStatusFilter filter) { this.filter = filter; } }

Click on the filter button

Page 126: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class FilterItems implements Task {

private final String filter;

public <T extends Actor> void performAs(T theActor) { theActor.attemptsTo( Click.on(TodoList.FILTER.of(filter) ); }

public static FilterItems toShow(String filter) { return instrumented(FilterItems.class, status); } public FilterItems(TodoStatusFilter filter) { this.filter = filter; } }

Pass in the name of the filter

Page 127: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class FilterItems implements Task {

private final String filter;

public <T extends Actor> void performAs(T theActor) { theActor.attemptsTo( Click.on(TodoList.FILTER.of(filter) .called(“filter by "+ filter)) ); }

public static FilterItems toShow(String filter) { return instrumented(FilterItems.class, status); } public FilterItems(TodoStatusFilter filter) { this.filter = filter; }

How will this interaction appear in the reports?

Page 128: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class FilterItems implements Task {

private final String filter;

@Step("{0} filters items by #filter") public <T extends Actor> void performAs(T theActor) { theActor.attemptsTo( Click.on(TodoList.FILTER.of(filter) .called(“filter by "+ filter)) ); }

public static FilterItems toShow(String filter) { return instrumented(FilterItems.class, status); }

How will this task appear in the reports

Page 129: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Actors ask questionsand verify the answers

Page 130: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );

Page 131: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );

A Consequence

Page 132: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );

A Question

Page 133: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );

A Hamcrest Matcher

Page 134: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );

Page 135: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(textOf(JourneyResults.HEADER), is("Journey Results")) );

Page 136: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(selectedValueOf(JourneyPlanner.SELECTED_DEPARTURE_TIME), is("Journey Results"))

);

Page 137: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat("the fastest tube line”, TheFastest.tubeLine(), is("Jubilee line to Canary Wharf”)) );

Page 138: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat("the fastest tube line", TheFastest.tubeLine(), is("Jubilee line to Canary Wharf")), seeThat("the departure time", TheFastest.departureTime(), is("08:59")), seeThat("the arrival time", TheFastest.arrivalTime(), is(“09:09")) );

Page 139: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat("the fastest tube line”, TheFastest.tubeLine(), is("Jubilee line to Canary Wharf”)) );

Page 140: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest { }

Page 141: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { } }

Page 142: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

Page 143: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

public class FastestTubeLineQuestion implements Question<String> { }

Page 144: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

public class FastestTubeLineQuestion implements Question<String> { @Override public String answeredBy(Actor actor) { } }

Page 145: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

public class FastestTubeLineQuestion implements Question<String> { @Override public String answeredBy(Actor actor) { return Text.of(JourneyResults.ITINERARY) } }

Page 146: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

public class FastestTubeLineQuestion implements Question<String> { @Override public String answeredBy(Actor actor) { return Text.of(JourneyResults.ITINERARY) .viewedBy(actor) } }

Page 147: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

public class FastestTubeLineQuestion implements Question<String> { @Override public String answeredBy(Actor actor) { return Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asString(); } }

Page 148: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }

@Subject("the fastest tube line") public class FastestTubeLineQuestion implements Question<String> { @Override public String answeredBy(Actor actor) { return Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asString(); } }

Page 149: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Or…

Page 150: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest { }

Page 151: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { } }

Page 152: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) } }

Page 153: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) } }

Page 154: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class TheFastest {

public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asString(); } }

Page 155: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

connie.should( seeThat(“all the tube lines”, AllThe.tubeLines(), contains("Northern line to Moorgate”)) );

Page 156: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class AllThe {

public static Question<String> tubeLine() { } }

Page 157: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class AllThe {

public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) } }

Page 158: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class AllThe {

public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) } }

Page 159: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class AllThe {

public static Question<List<String>> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asList(); } }

Page 160: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

The end result

Page 161: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@Managed WebDriver browser;

@Test public void should_show_the_soonest_departure_time_close_to_the_requested_time() {

Actor connie = Actor.named("Connie"); connie.can(BrowseTheWeb.with(browser));

connie.attemptsTo( OpenApplication.onTheJourneyPlannerPage(), ChooseOrigin.of("Waterloo"), ChooseDestination.of("Canary Wharf"), ChooseTimeOfDeparture.of("09:00"), Confirm.journeyDetails() );

connie.should( seeThat("the fastest tube line", TheFastest tubeLine(), is("Jubilee line to Canary Wharf")), seeThat("the departure time", TheFastest.departureTime(), is("08:59")), seeThat("the arrival time", TheFastest.arrivalTime(), is("09:09")) ); }

Page 162: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

But wait! There’s more!

Page 163: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@Managed WebDriver browser;

@Test public void should_show_the_soonest_departure_time_close_to_the_requested_time() {

Actor connie = Actor.named("Connie"); connie.can(BrowseTheWeb.with(browser));

connie.attemptsTo( OpenApplication.onTheJourneyPlannerPage(), ChooseOrigin.of("Waterloo"), ChooseDestination.of("Canary Wharf"), ChooseTimeOfDeparture.of("09:00"), Confirm.journeyDetails() );

connie.should( seeThat("the fastest tube line", TheFastest tubeLine(), is("Jubilee line to Canary Wharf")), seeThat("the departure time", TheFastest.departureTime(), is("08:59")), seeThat("the arrival time", TheFastest.arrivalTime(), is("09:09")) ); }

Page 164: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@Managed WebDriver browser;

@Test public void should_show_the_soonest_departure_time_close_to_the_requested_time() {

Actor connie = Actor.named("Connie"); connie.can(BrowseTheWeb.with(browser));

connie.attemptsTo( PlanAJourney.from("Waterloo").to("Canary Wharf").departingAt("09:00") );

connie.should( seeThat("the fastest tube line", TheFastest tubeLine(), is("Jubilee line to Canary Wharf")), seeThat("the departure time", TheFastest.departureTime(), is("08:59")), seeThat("the arrival time", TheFastest.arrivalTime(), is("09:09")) ); }

Page 165: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Working with Cucumber

Page 166: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Feature: Plan a new journey

Scenario: Plan a new journey Given that Connie is a London commuter When she plans a journey from Waterloo to Canary Wharf departing at 09:00 Then she should see that the fastest train departs at 08:59

Page 167: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }

Page 168: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }

@Given("^that (.*) is a London commuter$") public void a_london_commuter_named(String commuterName) throws Throwable { theActorCalled(commuterName); }

Page 169: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }

@Given("^that (.*) is a London commuter$") public void a_london_commuter_named(String commuterName) throws Throwable { theActorCalled(commuterName); }

Page 170: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Feature: Plan a new journey

Scenario: Plan a new journey Given that Connie is a London commuter When she plans a journey from Waterloo to Canary Wharf departing at 09:00 Then she should see that the fastest train departs at 08:59

Page 171: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }

@Given("^that (.*) is a London commuter$") public void a_london_commuter_named(String commuterName) throws Throwable { theActorCalled(commuterName); }

@When("^(.*) plans a journey from (.*) to (.*) departing at (.*)$") public void plan_a_journeys(String name, String departure, String destination, String departureTime) throws Throwable { theActorCalled(name).attemptsTo( PlanAJourney.from(departure).to(destination).departingAt(departureTime)

); }

Page 172: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Feature: Plan a new journey

Scenario: Plan a new journey Given that Connie is a London commuter When she plans a journey from Waterloo to Canary Wharf departing at 09:00 Then she should see that the fastest train departs at 08:59

Page 173: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }

@Given("^that (.*) is a London commuter$") public void a_london_commuter_named(String commuterName) throws Throwable {…}

@When("^(.*) plans a journey from (.*) to (.*) departing at (.*)$") public void plan_a_journeys(String name, String departure, String destination, String departureTime) throws Throwable {…}

@Then("^(.*) should see that the fastest train departs at (.*)$") public void should_see_departure_time(String name, String expectedDepartureTime) throws Throwable { theActorCalled(name).should( seeThat("the departure time", TheFastest.departureTime(), is(expectedDepartureTime)) );

Page 174: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Cucumber gives us flexibility

Page 175: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Feature: Plan a new journey

Scenario Outline: Plan many a journey Given that Connie is a London commuter When she plans a journey from <departure> to <destination> departing at <plannedDepartureTime> Then she should see a trip on the <line> line departing at <departureTime> Examples: | departure | destination | line | plannedDepartureTime | departureTime | | Waterloo | Canary Wharf | Jubilee line to Canary Wharf | 09:00 | 08:59 | | London Bridge | Moorgate | Northern line to Moorgate | 10:00 | 09:59 |

Page 176: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Feature: Plan a new journey

Scenario Outline: Plan many a journey Given that Connie is a London commuter When she plans a journey from <departure> to <destination> departing at <plannedDepartureTime> Then she should see a trip on the <line> line departing at <departureTime> Examples: | departure | destination | line | plannedDepartureTime | departureTime | | Waterloo | Canary Wharf | Jubilee line to Canary Wharf | 09:00 | 08:59 | | London Bridge | Moorgate | Northern line to Moorgate | 10:00 | 09:59 |

Page 177: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

@Then("^(.*) should see a trip on the (.*) line departing at (.*)") public void should_see_trip(String name, String line, String departureTime) { theActorCalled(name).should( seeThat("the fastest tube line”, TheFastest.tubeLine(), is(line)), seeThat("the departure time", TheFastest.departureTime(), is(departureTime)) ); }

Page 178: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Scenario: Coordinating journeys Given that Connie is a London commuter And that Charles is a London commuter When Connie plans a journey from Waterloo to Canary Wharf departing at 09:00 And Charles plans a journey from London Bridge to Moorgate departing at 10:00 Then Connie should see a trip on the Jubilee line to Canary Wharf line departing at 08:59 And Charles should see a trip on the Northern line to Moorgate line departing at 09:59

Page 179: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Obsess about reporting!

Page 180: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Levels of communication

-

+

Page 181: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

10,000 ft Release Readiness

Page 182: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

1000 ft Capabilities and Features

Page 183: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

100 ft Scenarios and Steps

Page 184: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

Release Readiness

Page 185: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

Release ReadinessCapabilities

Page 186: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

Release ReadinessCapabilitiesFeatures

Page 187: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

-

+

Release ReadinessCapabilitiesFeaturesScenarios

Page 188: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Questions to ask:- How much time do I spend maintaining the tests?- Am I modelling user’s interactions with the system,

or how the system is built?- Can I share elements of my testing framework with others?- How much duplication and dead code is there in my tests?- How long would it take me to find the issue if a test fails?- How long to change the tests when the system changes?- Can I use my tests to drive the design of the system?

Page 189: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Make your testsscalable by design

Page 190: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Prefer JavaScript?

Tryhttp://serenity-js.org

Page 191: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Jan Molak

Original slides and demonstration in JavaScript designed by

consultant, trainer, lead developer of Serenity/JS

Page 192: Sustainable Test Automation with Serenity BDD and Screenplay

serenity-bdd.info #SerenityBDD @Wakaleo

Thank you!Learn more at serenity-bdd.info

Source code:How we can help:Get in touch: Learn Serenity BDD online

bit.ly/serentiy-plannerjohnfergusonsmart.comreachme@johnfergusonsmart.comhttp://serenity-dojo.com