• Like

BDD, ATDD, Page Objects: The Road to Sustainable Web Testing

  • 5,551 views
Uploaded on

In this presentation we discuss techniques and case studies of automating web testing using BDD and ATDD tools and techniques.

In this presentation we discuss techniques and case studies of automating web testing using BDD and ATDD tools and techniques.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
5,551
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
171
Comments
0
Likes
15

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. BDD, ATDD, Page Objects The Road to Sustainable Web Testing John Ferguson Smart
  • 2. So who is this guy, anyway? Consulta nt Trainer Mentor Author Speaker Coder John Fer guson S mar t
  • 3. Java Power Tools Bootcamp at Skills Matter ALL YOUR AGILE JAVA TOOLS TRAINING ARE BELONG TO US bDr iver m  2/We mave Seleniu Hudson n BDD JUnit TD D London January 24-28 2011
  • 4. Don’t let your web tests end up like this!
  • 5. The Three Ways of Automated Web Testing Record/Replay Scripting Page Objects
  • 6. Record-replay automated tests Promise Reality
  • 7. Record-replay automated tests
  • 8. Script-based automated tests Selenium RC HTMLUnit JWebUnit Canoe Webtest Watir
  • 9. Script-based automated tests Selenium RC HTMLUnit JWebUnit Canoe Webtest Watir
  • 10. What we’d like to have... D.R.Y Don’t Repeat Yourself
  • 11. What we’d like to have... Reusable building blocks
  • 12. What we’d like to have... A communication tool
  • 13. Introducing Page Objects Reusable Low maintenance Speak your language
  • 14. Page Objects are reusable components
  • 15. Page Objects hide unnecessary details
  • 16. Page Objects are low maintenance
  • 17. Page Objects speak everybody’s language
  • 18. Page Objects in action An example
  • 19. Page Objects in action The old way - Selenium RC selenium = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.google.com/"); selenium.open("http://www.google.com"); selenium.waitForPageToLoad(5000); selenium.type("q", "cats"); selenium.click("BtnG"); selenium.waitForPageToLoad(5000); assertThat(selenium.isTextPresent("cats"), is(true));
  • 20. Page Objects in action The new way - Using Page Objects WebDriver driver = new FirefoxDriver(); GoogleSearchPage page = new GoogleSearchPage(driver); page.open(); page.searchFor("cats"); assertThat(page.getTitle(), containsString("cats") ); page.close();
  • 21. Page Objects in action The new way - Using Page Objects WebDriver driver = new FirefoxDriver(); GoogleSearchPage page = new GoogleSearchPage(driver); page.open(); page.searchFor("cats"); assertThat(page.getTitle(), containsString("cats") ); page.close(); GoogleSearchPage open() close() searchFor( query : String ) clickOnFeelingLucky() openAdvancedSearchOptions() ...
  • 22. Page Objects in action The new way - another example WebDriver driver = new FirefoxDriver(); GoogleSearchPage page = new GoogleSearchPage(driver); Hides HTML page.open() details page.typeIntoSearchBox("cats"); List<String> suggestions = page.getSuggestions(); Uses assertThat(suggestions, hasItem("cats and dogs")); business terms page.close();
  • 23. From Pages Objects to BDD Taking expressive tests to the next level
  • 24. BDD in action WebDriver driver = new FirefoxDriver(); GoogleSearchPage page = new GoogleSearchPage(driver); page.open() page.typeIntoSearchBox("cats"); List<String> suggestions = page.getSuggestions(); assertThat(suggestions, hasItem("cats and dogs")); page.close(); But would your testers understand this?
  • 25. BDD in action Much more readable using "google-search" scenario "Searching for 'cats' on Google", { when "the user types 'cats' in the search box", { onTheWebPage.typeIntoSearchBox "cats" } then "the drop-down suggestions should include 'cats and dogs'" theWebPage.suggestions.shouldHave "cats and dogs" } } Still uses Page Objects under the hood How about this?
  • 26. BDD in action More readable reporting
  • 27. So how does it work? Easyb Plugin using "google-search" scenario "Searching for 'cats' on Google",{ when "the user types 'cats' in the search box", { onTheWebPage.typeIntoSearchBox "cats" } then "the drop-down suggestions should include 'cats and dogs'" theWebPage.suggestions.shouldHave "cats and dogs" } } Page Objects Page Navigation
  • 28. Automated Acceptance Tests Where are your goal posts?
  • 29. Automated Acceptance Tests Unit tests are for Acceptance tests are developers for everyone else
  • 30. Automated Acceptance Tests Unit tests are for Acceptance tests are developers for everyone else
  • 31. Automated Acceptance Tests Passing acceptance tests Pending acceptance tests
  • 32. Automated Acceptance Tests Acceptance tests Pending acceptance tests
  • 33. Automated Acceptance Tests tags ["acceptance", "sprint-1"] Implement these in scenario "An empty grid should produce an empty grid",{ Sprint 1 when "the user chooses to start a new game", { newGamePage = homePage.clickOnNewGameLink() } then "the user is invited to enter the initial state of the universe", { newGamePage.text.shouldHave "Please seed your universe" } } scenario "The user can seed the universe with an initial grid",{ given "the user is on the new grid page", { newGridPage = homePage.clickOnNewGameLink() } when "that the user clicks on Go without picking any cells", { gridDisplayPage = newGridPage.clickOnGoButton() } then "the application will display an empty universe", { String[][] anEmptyGrid = [[".", ".", "."], [".", ".", "."], [".", ".", "."]] gridDisplayPage.displayedGrid.shouldBe anEmptyGrid } }
  • 34. And now for the case studies
  • 35. Case Study Government online form processing
  • 36. Architecture - fitting it all together Acceptance tests Easyb Plugin Page Objects Integration tests JUnit Web Application
  • 37. The application Perl and Java Lots of forms Ugly colours
  • 38. What the tester uses using "ecert" Custom easyb plugin tags "TC02" Plugin handles before "we are connected to the UAT environment", { authentication given "we are connected to the UAT environment", { connecting.to('uat').withUser('a_tester') } } Business-level tests scenario "The user opens the 'New Export Certificate' page and selects a country",{ when "the user clicks on the 'New Export Certificate' menu", { onTheWebPage.navigationPanel.clickOnNewExportCertificate() } and "the user chooses USA and clicks on 'Show Data Entry'", { onTheWebPage.selectDeclarationFormFor 'United States' } then "we should be on the US Export Certification Preparation page", { theWebPage.asText.shouldHave "Export Certificate Preparation" theWebPage.asText.shouldHave "Declarations for United States" } and "the 'Raise New Blank Export Certificate' is default and selected", { theWebPage.raiseNewBlankCertificate.shouldBeSelected() } }
  • 39. More nice screens
  • 40. What the tester uses ... scenario "The user fills in the Export Certificate Submission Form",{ when "we fill in the export certificate details", { theWebPage.with { certificateNumber = '123456' consignor = 'LANEXCO1' importerID = '123' Groovy shortcuts importerName = 'ImportsRUs' importerRepresentative = 'local guy' officialInformation = 'very important' transportMode = 'AIR' carrierName = 'AirNZ' Business-level tests productItem(1).description = 'Product data' productItem(1).harmonizedSystemCode = '020110' productItem(1).with { process(1).with { type = 'Freezing' processingStartDate = '01/01/2010' Handling processingEndDate = '02/01/2010' nested forms appliedBy = 'some dude' overrideSelected() } ...
  • 41. What the Page Objects look like public class ECertNavigationPanel extends AuthenticatedWebPage { @FindBy(linkText="XML Submit") WebElement xmlSubmit; WebDriver annotations @FindBy(linkText="New Export Certificate") WebElement newExportCertificate; public ECertNavigationPanel(WebDriver driver) { super(driver); } public WebElement getXmlSubmit() {...} public WebElement getNewExportCertificate() {...} public ECertSubmitXmlPage clickOnXmlSubmit() {...} public ExportCertificatePreparationPage clickOnNewExportCertificate() {...} }
  • 42. Case Study Class Report An online reporting tool for lawyers h"p://customfirst.com
  • 43. Architecture - fitting it all together Regression/ Integration tests Page Objects Web Application
  • 44. The application RUI Application Lots of AJAX !
  • 45. What the tests look like @Mixin (SeleniumTest) class ReportViewerTests extends AbstractSeleniumBaseTest { ViewerPage viewerPage Setting up the public void setUp() { super.setUp() Page Object TestFixtures.loadData() viewerPage = new ViewerPage(selenium, contextPath) viewerPage.openHomePage() } public void testClickingGLReportsIconShouldDisplaySubFolders() { viewerPage.clickFolderOpenIcon("GL Reports") assertTrue viewerPage.folderPresent("Accounts") Testing the app assertTrue viewerPage.folderPresent("Test Reports") } public void testClickingOnASubFolderShouldDisplayReports() { viewerPage.clickFolderOpenIcon("GL Reports") assertTrue viewerPage.folderPresent("Test Reports") viewerPage.clickFolder "Test Reports" assertTrue viewerPage.reportRowPresent("Test Reports","Aged Debtors By Client") assertTrue viewerPage.reportRowPresent("Test Reports","Chart") } ...
  • 46. What the Page Objects look like class ViewerPage extends AbstractPageObject{ public ViewerPage(def selenium, def contextPath) { Business-friendly super(selenium, contextPath) } methods public void clickFolder(String folderName) {...} public void clickFolderOpenIcon(String folderId) {...} public boolean folderPresent(String folderName){...} public boolean reportRowPresent(String folder,String rowName){...} public boolean reportParameterPresent(String reportName,String parameterName){...} public boolean reportRowTextPresent(String folder,String reportName,String text){...} ...
  • 47. Case Study Financial software
  • 48. The application Looks a bit like this one... (but more complex) (and top secret) (Shhhhhh!) Again, lots of AJAX !
  • 49. Page Components Reusable component class RadioButton { WebElement button WebElement buttonContainer; def buttonId def driver void clickButton() { initButton() button.click(); } void shouldBeEnabled() { assert !isDisabled(); } void shouldBeDisabled() { assert isDisabled(); } Horrible nasty GWT code private boolean isDisabled() { initButton() return buttonContainer.getAttribute("class").contains("x-item-disabled"); } private void initButton() { if (button==null) { buttonContainer=driver.findElement(By.id("gwt-debug-${buttonId}_BUTTON")); button=driver.findElement(By.xpath("//input[contains(@value, ${buttonId}-input)]")); } } }
  • 50. Page Components @Test public void userShouldBecomeOwnerOfCurrentWorkItem() { page.workItemTree.selectEntryCalled("Stuff to do") ... page.assignButton.shouldBeEnabled() page.assignButton.click(); Click on a button page.assignButton.shouldBeHidden(); page.retryButton.shouldBeEnabled(); page.saveButton.shouldBeDisabled() page.saveButton.shouldBePresent(); Custom asserts } scenario "No work items should initially appear on the screen",{ when "the user opens the page", { page.open() } and "the Item Tree 'Show all' check box should not be ticked", { assert page.itemTree.showAll.isNotChecked() } and "the Item Tree should contain no work items", { assert page.itemTree.isEmpty() } } BDD-style tests
  • 51. Page Components class Grid { A Grid (table) component def driver def gridId def getAt(int i) { It looks like an array def gridRows = getGridRows() return gridRows[i] } def size() { def gridRows = getGridRows() return gridRows.size() } def shouldHaveARowWith(def map) { def gridRows = getGridRows() def matchingRowFound = true for(entry in map) { def gridRow = gridRows.find { row -> row[entry.key] == entry.value } matchingRowFound = gridRow != null } return matchingRowFound }
  • 52. Page Components @Test void theSummaryItemChangesToReflectTreeChoice() { page.itemTree.selectEntryCalled("Stuff to do") This is not an array assert page.itemSummaryGrid.size() == 1 def highlightedItemSummaryRow = page.itemSummaryGrid[0] assert highlightedItemSummaryRow.customerName == "ACME Inc" }
  • 53. ATDD, BDD and Page Objects Clean, precise, well-designed Powerful, robust, low-maintenance John  Ferguson  Smart Email:  john.smart@wakaleo.com Web:  h"p://www.wakaleo.com Twi"er:  wakaleo