Sustainable Test Automation with Serenity BDD and Screenplay
-
Upload
john-ferguson-smart-limited -
Category
Technology
-
view
360 -
download
6
Transcript of Sustainable Test Automation with Serenity BDD and Screenplay
serenity-bdd.info #SerenityBDD @Wakaleo
Sustainable Test Automationwith 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
serenity-bdd.info #SerenityBDD @Wakaleo
serenity-bdd.info #SerenityBDD @Wakaleo
serenity-bdd.info #SerenityBDD @Wakaleo
Want to follow along?
bit.ly/serentiy-planner
serenity-bdd.info #SerenityBDD @Wakaleo
Execution time: minutes → hours
Writing: hours → days
serenity-bdd.info #SerenityBDD @Wakaleo
Execution time: minutes → hours
Writing: hours → days
Analysis and reporting: hours → days
serenity-bdd.info #SerenityBDD @Wakaleo
Execution time: minutes → hours
Writing: hours → days
Analysis and reporting: hours → days
Maintenance: days → weeks
serenity-bdd.info #SerenityBDD @Wakaleo
The difference between scalable tests
and a world of pain is design.
#SerenityBDD @Wakaleo serenity-bdd.info
#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.
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo”
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼ Press ↩
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo Enter “Waterloo” Pick the first suggestion Wait for the suggestions Press ▼ Press ↩
#SerenityBDD @Wakaleo serenity-bdd.info
Open the Journey PlannerChoose origin: Waterloo
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary Wharf
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary Wharf
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM
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
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
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”
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AM
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection
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”
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
serenity-bdd.info #SerenityBDD @Wakaleo
Open the Journey PlannerChoose origin: WaterlooChoose destination: Canary WharfChoose time of departure: 9:00 AMConfirm selection
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
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");
serenity-bdd.info #SerenityBDD @Wakaleo
browser.get("https://tfl.gov.uk/");
serenity-bdd.info #SerenityBDD @Wakaleo
browser.get(“https://tfl.gov.uk/");browser.findElement(origin).sendKeys("Waterloo");
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));
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);
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");
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);
serenity-bdd.info #SerenityBDD @Wakaleo
…browser.findElement(changeTimeLink).click();browser.findElement(leavingButton).click();new Select(browser.findElement(timeSelector)) .selectByVisibleText("09:00");
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));
serenity-bdd.info #SerenityBDD @Wakaleo
…String fastestDepartureTime = startTimeOf(browser.findElement(fastestJourney).getText());
assertThat(fastestDepartureTime).isEqualTo("08:59");
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 ?
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());
#SerenityBDD @Wakaleo
“
serenity-bdd.info
If you have WebDriver APIs in your test methods, You’re Doing It Wrong!- Simon Stewart, creator of WebDriver
serenity-bdd.info #SerenityBDD @Wakaleo
serenity-bdd.info #SerenityBDD @Wakaleo
@DefaultUrl(“https://tfl.gov.uk")public class JourneyPlannerPage extends PageObject { // Locators // Actions}
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; …
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() {…}}
serenity-bdd.info #SerenityBDD @Wakaleo
@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest {
serenity-bdd.info #SerenityBDD @Wakaleo
@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest { @Managed WebDriver driver;
serenity-bdd.info #SerenityBDD @Wakaleo
@RunWith(SerenityRunner.class) public class JourneyPlannerWithPageObjectsTest { @Managed WebDriver driver;
JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;
serenity-bdd.info #SerenityBDD @Wakaleo
JourneyPlannerPage journeyPlanner; JourneyResultsPage journeyResults;
journeyPlanner.open(); journeyPlanner.chooseOriginOf(“Waterloo"); journeyPlanner.chooseDestinationOf("Canary Wharf”); journeyPlanner.chooseTimeOfDeparture(“09:00”); journeyPlanner.confirmSelection();
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");
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!
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"); } }
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
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)); }
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)); }
serenity-bdd.info #SerenityBDD @Wakaleo
Four Software Engineering Principles can help you write more maintainable tests
serenity-bdd.info #SerenityBDD @Wakaleo
1) Separation of ConcernsHide complexity through layers of abstraction
serenity-bdd.info #SerenityBDD @Wakaleo
2) Single Responsibility PrincipleA class should have only one reason to change
serenity-bdd.info #SerenityBDD @Wakaleo
3) Open-Closed PrincipleGreen diffs
serenity-bdd.info #SerenityBDD @Wakaleo
4) Narrative coding styleExpress your intent
serenity-bdd.info #SerenityBDD @Wakaleo
Serenity BDD andthe Screenplay Pattern
#SerenityBDD @Wakaleo
“
serenity-bdd.info
Your test framework should not model how your system behaves. It should model how your user behaves.
serenity-bdd.info #SerenityBDD @Wakaleo
serenity-bdd.info #SerenityBDD @Wakaleo
GoalsWhat are you trying to achieve?
serenity-bdd.info #SerenityBDD @Wakaleo
GoalsWhat are you trying to achieve?
Tasks What do you need to do to achieve this goal?
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?
serenity-bdd.info #SerenityBDD @Wakaleo
Plan my journey
Actor Goals
Connor the commuter
serenity-bdd.info #SerenityBDD @Wakaleo
Plan my journey
Actor Goals Tasks
Choose Destination
Choose Origin
Choose time of departure
Confirm selection
Connor the commuter
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
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
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"))
serenity-bdd.info #SerenityBDD @Wakaleo
public class ChooseOrigin implements Task { }
serenity-bdd.info #SerenityBDD @Wakaleo
public class ChooseOrigin implements Task {
@Override public <T extends Actor> void performAs(T actor) {} }
serenity-bdd.info #SerenityBDD @Wakaleo
public class ChooseOrigin implements Task {
@Override public <T extends Actor> void performAs(T actor) { actor.attemptsTo( ); } }
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) ); } }
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()) ); } }
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(), ); } }
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; }
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;}
}
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); } }
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); } }
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
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
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
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", } }
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), } }
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()) } }
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(), } }
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)) } }
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); } }
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)
serenity-bdd.info #SerenityBDD @Wakaleo
import net.serenitybdd.screenplay.Actor;
Actor connie = Actor.named("Connie");
serenity-bdd.info #SerenityBDD @Wakaleo
import net.serenitybdd.screenplay.Actor;
Actor connie = Actor.named("Connie");
connie.attemptsTo( //…);
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()
serenity-bdd.info #SerenityBDD @Wakaleo
Actors have abilities that enable interactions
with the system
serenity-bdd.info #SerenityBDD @Wakaleo
@Managed WebDriver browser;
Actor connie = Actor.named("Connie"); connie.can(BrowseTheWeb.with(browser));
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");;
}
serenity-bdd.info #SerenityBDD @Wakaleo
Target.the("Departure station").locatedBy("#InputFrom");
serenity-bdd.info #SerenityBDD @Wakaleo
Target.the("Departure station").locatedBy("#InputFrom");
How should this element be named in the reports?
serenity-bdd.info #SerenityBDD @Wakaleo
Target.the("Departure station").locatedBy("#InputFrom");
How should we locate it?
serenity-bdd.info #SerenityBDD @Wakaleo
Target FILTER = Target.the(“filter") .locatedBy("//*[@class='filters']//a[.='{0}']");
This value will be provided
serenity-bdd.info #SerenityBDD @Wakaleo
theActor.attemptsTo(FilterItems.toShow(“Completed"));
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; } }
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
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
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?
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
serenity-bdd.info #SerenityBDD @Wakaleo
Actors ask questionsand verify the answers
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );
A Consequence
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );
A Question
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );
A Hamcrest Matcher
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(the(JourneyResults.HEADER), isVisible()) );
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(textOf(JourneyResults.HEADER), is("Journey Results")) );
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(selectedValueOf(JourneyPlanner.SELECTED_DEPARTURE_TIME), is("Journey Results"))
);
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat("the fastest tube line”, TheFastest.tubeLine(), is("Jubilee line to Canary Wharf”)) );
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")) );
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat("the fastest tube line”, TheFastest.tubeLine(), is("Jubilee line to Canary Wharf”)) );
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { return new FastestTubeLineQuestion(); } }
public class FastestTubeLineQuestion implements Question<String> { }
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) { } }
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) } }
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) } }
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(); } }
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(); } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class TheFastest {
public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asString(); } }
serenity-bdd.info #SerenityBDD @Wakaleo
connie.should( seeThat(“all the tube lines”, AllThe.tubeLines(), contains("Northern line to Moorgate”)) );
serenity-bdd.info #SerenityBDD @Wakaleo
public class AllThe {
public static Question<String> tubeLine() { } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class AllThe {
public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class AllThe {
public static Question<String> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) } }
serenity-bdd.info #SerenityBDD @Wakaleo
public class AllThe {
public static Question<List<String>> tubeLine() { return actor -> Text.of(JourneyResults.ITINERARY) .viewedBy(actor) .asList(); } }
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")) ); }
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")) ); }
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")) ); }
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
serenity-bdd.info #SerenityBDD @Wakaleo
public class PlanAJourneyStepDefinitions { @Before public void set_the_stage() { OnStage.setTheStage(new OnlineCast()); }
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); }
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); }
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
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)
); }
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
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)) );
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 |
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 |
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)) ); }
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
serenity-bdd.info #SerenityBDD @Wakaleo
-
+
1000 ft Capabilities and Features
serenity-bdd.info #SerenityBDD @Wakaleo
-
+
Release ReadinessCapabilitiesFeatures
serenity-bdd.info #SerenityBDD @Wakaleo
-
+
Release ReadinessCapabilitiesFeaturesScenarios
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?
serenity-bdd.info #SerenityBDD @Wakaleo
Prefer JavaScript?
Tryhttp://serenity-js.org
serenity-bdd.info #SerenityBDD @Wakaleo
Jan Molak
Original slides and demonstration in JavaScript designed by
consultant, trainer, lead developer of Serenity/JS
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