Web UI Testing
Colin Harrington
June 12th 2013
BITS
$ whoami
Colin Harrington
@ColinHarrington
colin.harrington@objectpartners.com
Principal Consultant
Object Partners Inc
-
Java, Groovy, JavaScript, Mobile, Open Source
-
~100 Senior Consultants
- Minneapolis, Omaha
- Chicago, Denver
- Average Tenure Over 5 years
- Founded 1996
Browser Ubiquity
WEB UI = Modern App Platform
JavaScript Engines
HTML5 / CSS3
Browsers
Chrome
Firefox
Internet Exploder
Safari
Mobile!
Native vs Web
Functional Testing
Testing Paradigms
{ Unit, Integration, Functional }
http://commons.wikimedia.org/wiki/File:Prism-rainbow.svg
... Testing Perspectives
Smoke
Cluster
Permutation
Periodic
Performance
Load
Stress/Failure
Penetration
Regression
Manual
API
3rd party
Users *are* Test Subjects
Testing Discipline
Deserves a Seat at the table
γνῶθι σεαυτόν
Know t̶h̶y̶s̶e̶l̶f̶ your tools
Tools
Learn
Invest
Practice
Share
Express Intent
Good
when:
doUserLogIn()
expect:
at HomePage
more verbose
// The Firefox driver supports javascript
WebDriver driver = new FirefoxDriver();
// Go to the Google Suggest home page
driver.get("http://www.google.com/webhp?complete=1&hl=en");
// Enter the query string "Cheese"
WebElement query = driver.findElement(By.name("q"));
query.sendKeys("Cheese");
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
WebElement resultsDiv = driver.findElement(By.className("gssb_e"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
// And now list the suggestions
List<WebElement> allSuggestions = driver.findElements(By.xpath("//td[@class='gssb_a gbqfsf']"));
for (WebElement suggestion : allSuggestions) {
System.out.println(suggestion.getText());
}
driver.quit();
Reasonable Assurance
GEB
What is it?
Geb
(pronounced "jeb")
Geb
=
Webdriver
+
Groovy
+
JQuery like Content Selector
+
Page Object model
Geb in Action
WebDriver
Code -> Driving -> Real Browser
{ Chrome, Firefox, Internet Exploder,
Safari, PhantomJS, HtmlUnit,
Android, iOS, Remote }
2048
2048 solver
Basic Features
CSS Selectors
javascript access
form interaction
Basically anything a typical browser can do.
Page Object Pattern
class GoogleHomePage extends Page {
static url = "http://google.com/?complete=0"
static at = { title == "Google" }
static content = {
searchField { $("input[name=q]") }
searchButton(to: GoogleResultsPage) { $("input[value='Google Search']") }
}
void search(String searchTerm) {
searchField.value searchTerm
searchButton.click()
}
}
class GoogleResultsPage extends Page { ... }
Browser.drive {
to GoogleHomePage
search "Chuck Norris"
at GoogleResultsPage
resultLink(0).text().contains("Chuck")
}
Content
class GoogleHomePage extends Page {
static url = "http://google.com/?complete=0"
static at = { title == "Google" }
static content = {
searchField { $("input[name=q]") }
searchButton(to: GoogleResultsPage) {
$("input[value='Google Search']")
}
}
void search(String searchTerm) {
searchField.value searchTerm
searchButton.click()
}
}
Accessible via
page.searchField
class GoogleHomePage extends Page { static url = "http://google.com/?complete=0" static at = { title == "Google" } static content = { searchField { $("input[name=q]") } searchButton(to: GoogleResultsPage) {
$("input[value='Google Search']")
} } void search(String searchTerm) { searchField.value searchTerm searchButton.click() } }
page.searchField
Modules
Think Templates
Reusable modules that exist across multiple page hierarchies.
Header panel
class ExampleModule extends Module {
static content = {
button { $("input", type: "submit") }
}
}
class ExamplePage extends Page {
static content = {
theModule { module ExampleModule }
}
}
class ExampleModule extends Module {
static content = {
button { $("input", type: "submit") }
}
}
class ExamplePage extends Page {
static content = {
theModule { module ExampleModule }
}
}
Reporters
Source
Screenshots
Remote WebDriver
-
Install and run the Remote WebDriver client/server
-
Opens a port
-
listens for commands
http://www.objectpartners.com/2012/04/24/start-building-out-automated-groovy-mobile-web-application-testing-on-your-iphone-or-ipad-with-geb-and-spock/
-
Install and run the Remote WebDriver client/server
-
Opens a port
-
listens for commands
combinatorics
Browsers:
- Mobile / Desktop / Tablet
- OS / Version
- Browser / Version
- Viewport Resolution / DPI
Solutions
Lab of devices?
Virtual / hybrid Lab?
Outsource?
problems++
SauceLabs
"Run your web and mobile apptests across hundreds of realbrowsers and platforms instantly"
(basically all of 'em)
Secret Sauce
-
Screenshots
-
Videos
-
Private Reverse Tunneling
-
Free for OSS
Write Testable UIs
Semantic Markup
Consistent asynchronous activities
Loading indicators, keeping track of state.
Tests act as a user
Test your Javascript
Yes, Really
Test your Javascript
QUnit
jQuery
"Behavior-Driven JavaScript"
Mocha
Mocha is a feature-rich JavaScript test framework running on node.js and the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.
Test Runners
Testem
- Test-framework agnostic. Support for
- {Jasmine, QUnit, Mocha, Buster.js}
-
Others, through custom test framework adapters.
-
Run tests in all major browsers as well as Node and PhantomJS
-
Two distinct use-cases:
- Test-Driven-Development(TDD) — designed to streamline the TDD workflow
- Continuous Integration(CI) — designed to work well with popular CI servers like Jenkins or Teamcity
- Cross-platform support
- {OS X, Windows, Linux}
- Preprocessor support
- {CoffeeScript, Browserify, JSHint/JSLint, everything else}
Karma
-
Test on Real Devices
-
Remote Control
-
Testing Framework Agnostic
-
Open Source
-
Easy Debugging
-
Continuous Integration
Capture Client Errors
Feedback
Logging
Analytics
Questions?
Fin
Thank you!
Web UI Testing
By Colin Harrington
Web UI Testing
BITS in Omaha NE :: June 12th 2014
- 3,179