The document discusses moving beyond traditional page object models for testing dynamic web applications. It proposes modeling the UI with smaller "page components" that use method chaining and return types to better reflect the user experience. It also suggests using a component factory and locators to simplify test code and address issues like synchronization. The goal is to make tests more readable, reusable and robust as applications become more interactive.
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. 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. 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
20. How Do We Get
There?
• Refactoring
• Apply Design Patterns
• Continuous Improvement
Wednesday, 06 April, 2011
21. How Do We Get
There?
Wednesday, 06 April, 2011
22. Context
• Several consulting gigs over the past few
years
• Current client:
• consumer-facing RIA
• tests written with Selenium 1 API in Java
Wednesday, 06 April, 2011
23. PRO TIP
Use WebDriver
Wednesday, 06 April, 2011
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 things
Wednesday, 06 April, 2011
25. Page Object Benefits
• Readable tests
• Reduced or eliminated duplication
• Self-verification
• Reusability
Wednesday, 06 April, 2011
26. So Why Go “Beyond”?
Web Apps Are Different Now
Wednesday, 06 April, 2011
27. Why Go “Beyond”?
meh
OMG SOOO MUCH BETTER
Wednesday, 06 April, 2011
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. What’s This, Then?
I call them “Page Components”
Wednesday, 06 April, 2011
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. 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. Page Component
Recap
• Just like Page Objects... but littler
• Use return types to model the user
experience
Wednesday, 06 April, 2011
37. ComponentFactory
Do you like to type? I don’t.
Wednesday, 06 April, 2011
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. ComponentFactory
new IssueSummary(selenium).expand();
vs.
withComponent().issueSummary().expand();
Wednesday, 06 April, 2011
41. ComponentFactory
Recap
• Interactive documentation
• Easier entry point into component creation
• Another way to use strong typing to make
the tests easier to write
Wednesday, 06 April, 2011
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) .title
Wednesday, 06 April, 2011
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. 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. Synchronization Issues
Two kinds:
1. Element not present yet
2. Element content not updated yet
Wednesday, 06 April, 2011
48. Thread.sleep()
NO.*
STEP AWAY FROM THE KEYBOARD.
Wednesday, 06 April, 2011
49. Thread.sleep()
NO.*
STEP AWAY FROM THE KEYBOARD.
(*unless you have no other choice)
Wednesday, 06 April, 2011
50. Thread.sleep()
Just be sure to wrap it in an appropriately named method:
Wednesday, 06 April, 2011
51. Thread.sleep()
Just be sure to wrap it in an appropriately named method:
• sleepAsALastResortWhenNothingElseWorks()
Wednesday, 06 April, 2011
52. Thread.sleep()
Just be sure to wrap it in an appropriately named method:
• sleepAsALastResortWhenNothingElseWorks()
• sleepToMakeThisTestMoreFlakyThusEnsuringMyJobSecurity()
Wednesday, 06 April, 2011
53. Thread.sleep()
Just be sure to wrap it in an appropriately named method:
• sleepAsALastResortWhenNothingElseWorks()
• sleepToMakeThisTestMoreFlakyThusEnsuringMyJobSecurity()
• sleepBecauseImTooLazyToSolveThisProperly()
Wednesday, 06 April, 2011
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. Two Options
1. Subclass DefaultSelenium and override the
click() method
2. Extract a BaseComponent class that
provides a click() method for use by all
subclasses
Wednesday, 06 April, 2011
56. Next Issue
The element is present in the DOM, but
doesn't contain the right data yet.
Wednesday, 06 April, 2011
57. Cleanest Solution
Build the app for testability
Wednesday, 06 April, 2011
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. Final Thoughts
Beyond “Beyond”?
Wednesday, 06 April, 2011
60. Thank You!
http://electronicingenuity.com
dante@electronicingenuity.com
@dantebriones
Wednesday, 06 April, 2011
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