Beyond Page Objects

10,852 views

Published on

Published in: Technology
2 Comments
12 Likes
Statistics
Notes
No Downloads
Views
Total views
10,852
On SlideShare
0
From Embeds
0
Number of Embeds
3,782
Actions
Shares
0
Downloads
107
Comments
2
Likes
12
Embeds 0
No embeds

No notes for slide

Beyond Page Objects

  1. 1. Beyond Page Objects Dante Briones SeleniumConf 5 April 2011 http://electronicingenuity.com dante@electronicingenuity.com @dantebrionesWednesday, 06 April, 2011
  2. 2. Let’s Start With A StoryWednesday, 06 April, 2011
  3. 3. A long time ago* in an investment bank far, far away... *(2005)Wednesday, 06 April, 2011
  4. 4. Our HeroWednesday, 06 April, 2011
  5. 5. A Chance EncounterWednesday, 06 April, 2011
  6. 6. A New WeaponWednesday, 06 April, 2011
  7. 7. Engaging The EnemyWednesday, 06 April, 2011
  8. 8. Victory MUCH more readable!Wednesday, 06 April, 2011
  9. 9. What’s The Moral? (hint: it’s not about the developer, the author, or the book)Wednesday, 06 April, 2011
  10. 10. The DetailsWednesday, 06 April, 2011
  11. 11. Why Page Objects?Wednesday, 06 April, 2011
  12. 12. Why Page Objects?Wednesday, 06 April, 2011
  13. 13. Why Page Objects?Wednesday, 06 April, 2011
  14. 14. Tests Are Code They need TLCWednesday, 06 April, 2011
  15. 15. Readability selenium.click(“id=itemAction1138”); assertEquals(“1”, selenium.getText(“css=#cart .count”)); vs. item.clickAddToCart(); assertEquals(1, cart.getItemCount());Wednesday, 06 April, 2011
  16. 16. Stay DRY Test class: selenium.click(“id=zoom_out_action”); selenium.click(“id=zoom_out_action”); vs. Test class: map.zoomOut(); map.zoomOut(); Map class: selenium.click(“id=zoom_out_action”);Wednesday, 06 April, 2011
  17. 17. Robustitude Thread.sleep(250); //wait for button to appear selenium.click(“id=a_button”); Thread.sleep(500); //wait for results to show up assertEquals(selenium.getText(“id=results”), “False Negatives suck!”);Wednesday, 06 April, 2011
  18. 18. Sensible Names • catalogItem.addToCart() • blogEntry.post() • auction.bid(25.00)Wednesday, 06 April, 2011
  19. 19. Small ClassesWednesday, 06 April, 2011
  20. 20. How Do We Get There? • Refactoring • Apply Design Patterns • Continuous ImprovementWednesday, 06 April, 2011
  21. 21. How Do We Get There?Wednesday, 06 April, 2011
  22. 22. Context • Several consulting gigs over the past few years • Current client: • consumer-facing RIA • tests written with Selenium 1 API in JavaWednesday, 06 April, 2011
  23. 23. PRO TIP Use WebDriverWednesday, 06 April, 2011
  24. 24. Page Objects Recap • Model the application’s UI • Expose methods that reflect the things a user can see and do on that page • Hides the details of telling the browser how to do those thingsWednesday, 06 April, 2011
  25. 25. Page Object Benefits • Readable tests • Reduced or eliminated duplication • Self-verification • ReusabilityWednesday, 06 April, 2011
  26. 26. So Why Go “Beyond”? Web Apps Are Different NowWednesday, 06 April, 2011
  27. 27. Why Go “Beyond”? meh OMG SOOO MUCH BETTERWednesday, 06 April, 2011
  28. 28. Why Go “Beyond”?Wednesday, 06 April, 2011
  29. 29. Why Go “Beyond”? Because modern web apps are dynamic and richWednesday, 06 April, 2011
  30. 30. Example: Pivotal TrackerWednesday, 06 April, 2011
  31. 31. Wednesday, 06 April, 2011
  32. 32. Modeling The UI public class IssueSummary { public IssueDetail expand() {...} } public class IssueDetail { public void save() {...} public void cancel() {...} public String getStoryId() {...} }Wednesday, 06 April, 2011
  33. 33. What’s This, Then? I call them “Page Components”Wednesday, 06 April, 2011
  34. 34. Method Chaining: Focus Stays Put public class IssueDetail { public void save() {...} public IssueDetail addComment(String comment) { ... return this; } } issueDetail.addComment().save();Wednesday, 06 April, 2011
  35. 35. Method Chaining: Focus Moves Elsewhere public class IssueDetail { public ConfirmationDialog delete() { ... return new ConfirmationDialog(); } } issueDetail.delete().confirm(); or issueDetail.delete().cancel();Wednesday, 06 April, 2011
  36. 36. Page Component Recap • Just like Page Objects... but littler • Use return types to model the user experienceWednesday, 06 April, 2011
  37. 37. ComponentFactory Do you like to type? I don’t.Wednesday, 06 April, 2011
  38. 38. ComponentFactory 1/(keystrokes Job Satisfaction = required write useful code)Wednesday, 06 April, 2011
  39. 39. ComponentFactory public class ComponentFactory { public IssueSummary issueSummary() { return new IssueSummary(...); } } public abstract BaseTestCase { protected ComponentFactory withComponent() { return new ComponentFactory(); } }Wednesday, 06 April, 2011
  40. 40. ComponentFactory new IssueSummary(selenium).expand(); vs. withComponent().issueSummary().expand();Wednesday, 06 April, 2011
  41. 41. ComponentFactory Recap • Interactive documentation • Easier entry point into component creation • Another way to use strong typing to make the tests easier to writeWednesday, 06 April, 2011
  42. 42. Indexed ComponentsWednesday, 06 April, 2011
  43. 43. Indexed Components IssueSummary summary = withComponent().backlog().issueSummary(0); assertEquals(summary.getTitle(), “some title”);Wednesday, 06 April, 2011
  44. 44. Indexed Components CSS locators: Backlog = #backlog First issue summary = #backlog .issue-summary:nth(0) “Expand” button = #backlog .issue-summary:nth(0) .expand Title = #backlog .issue-summary:nth(0) .titleWednesday, 06 April, 2011
  45. 45. The Locator Class public class Locator { protected int index; public Locator(String rootLocator, int index) { this.rootLocator = rootLocator; this.index = index; } public String of(String containedElement) { return String.format(rootLocator, index) + " " + containedElement; } }Wednesday, 06 April, 2011
  46. 46. Using A Locator public IssueDetail expand() { selenium.click(“#backlog .issue-summary:nth(0) .expand”); ... } vs. public IssueDetail expand() { selenium.expand(locator.of(“.expand”)); ... }Wednesday, 06 April, 2011
  47. 47. Synchronization Issues Two kinds: 1. Element not present yet 2. Element content not updated yetWednesday, 06 April, 2011
  48. 48. Thread.sleep() NO.* STEP AWAY FROM THE KEYBOARD.Wednesday, 06 April, 2011
  49. 49. Thread.sleep() NO.* STEP AWAY FROM THE KEYBOARD. (*unless you have no other choice)Wednesday, 06 April, 2011
  50. 50. Thread.sleep() Just be sure to wrap it in an appropriately named method:Wednesday, 06 April, 2011
  51. 51. Thread.sleep() Just be sure to wrap it in an appropriately named method: • sleepAsALastResortWhenNothingElseWorks()Wednesday, 06 April, 2011
  52. 52. Thread.sleep() Just be sure to wrap it in an appropriately named method: • sleepAsALastResortWhenNothingElseWorks() • sleepToMakeThisTestMoreFlakyThusEnsuringMyJobSecurity()Wednesday, 06 April, 2011
  53. 53. Thread.sleep() Just be sure to wrap it in an appropriately named method: • sleepAsALastResortWhenNothingElseWorks() • sleepToMakeThisTestMoreFlakyThusEnsuringMyJobSecurity() • sleepBecauseImTooLazyToSolveThisProperly()Wednesday, 06 April, 2011
  54. 54. Use The Wait Class ...to delay the test until the app exhibits certain behavior rather than waiting for an arbitrary amount of time.Wednesday, 06 April, 2011
  55. 55. Two Options 1. Subclass DefaultSelenium and override the click() method 2. Extract a BaseComponent class that provides a click() method for use by all subclassesWednesday, 06 April, 2011
  56. 56. Next Issue The element is present in the DOM, but doesnt contain the right data yet.Wednesday, 06 April, 2011
  57. 57. Cleanest Solution Build the app for testabilityWednesday, 06 April, 2011
  58. 58. Next Best Solution public IssueDetail addComment() { int initialCount = getCommentCount(); selenium.type(locator.of(“.comment-entry”)); selenium.click(locator.of(“.add-comment”)); waitUntilCommentCountIs(initialCount + 1); return this; }Wednesday, 06 April, 2011
  59. 59. Final Thoughts Beyond “Beyond”?Wednesday, 06 April, 2011
  60. 60. Thank You! http://electronicingenuity.com dante@electronicingenuity.com @dantebrionesWednesday, 06 April, 2011
  61. 61. References • Dan North on Best Practices: • http://www.viddler.com/explore/kvarnhammar/videos/6/ • Adam Goucher on built-in test synchronization: • http://saucelabs.com/blog/index.php/2011/02/advanced-selenium- synchronization-with-latches/Wednesday, 06 April, 2011

×