web app testing with selenium
TRANSCRIPT
Web App Testing with Selenium
March 6th, 2008
João Prado MaiaLead Software Developer, Alert Logic
Slide: 2
Unit testing in PHP land• Unit testing OOP code
– usually just business logic code (classes)
• Not good enough– No way to test visual aspect of the app
• CSS
• Broken images
– How do you check JavaScript based pages?
– How about AJAX calls?
– Very labor intensive
Slide: 3
Combined approach• Unit testing of business logic code
– Data access classes
– Lots of best practices around for this
• UI testing with Selenium
– Make sure UI behaves correctly
• JavaScript based or not
– Examples:
• Log in to your app
• Log out from your app
• Change your account settings
• etc
Slide: 4
Enter Selenium!• Selenium Core
– JavaScript library– Used by all other sub-
projects
• Selenium IDE to record tests– Firefox extension– Playback tests– Debug and set breakpoints
• Selenium RC– Java server– Controls web browser
remotely
Slide: 5
Selenium IDE• Firefox extension
– Record and replay tests– Test files as HTML files (by default)
• Accepts commands, allowing you to:– Run actions on browser– Verify that document has valid content
• Run a suite of UI tests– Multiple tests running in sequence
Slide: 6
Recording and Replaying a Test•Demonstration
Slide: 7
Selenium test structure<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>google_houston</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">google_houston</td></tr></thead><tbody><tr>
<td>open</td><td>/</td><td></td>
</tr><tr>
<td>type</td><td>q</td><td>houston php</td>
</tr><tr>
<td>click</td><td>btnG</td><td></td>
</tr><tr>
<td>verifyTextPresent</td><td>Houston PHP / MySQL Users Group</td><td></td>
</tr></tbody></table></body></html>
Slide: 8
Understanding Selenium• Reference documentation
– http://release.openqa.org/selenium-core/0.8.2/reference.html
• Key concepts– Actions– Accessors– Assertions– Patterns– Locators
• Valid locators values:– id=nav_bar– name=username– dom=document.images[2]– xpath=//table[@id=“results”]/tr[1]/td[4]– css=a[href=“#top”]– link=Logout
Slide: 9
Running a Test Suite
• TestRunner interface– Run multiple tests in
sequence– Internal to Selenium
• Demonstration
Slide: 10
Test suite structure<table> <tr> <td>Meetup presentation</td> </tr> <tr> <td><a target="testFrame" href="google_smarty.html">Google -
smarty</a></td> </tr> <tr> <td><a target="testFrame" href="google_latest_php.html">Google -
latest php version</a></td> </tr> <tr> <td><a target="testFrame" href="google_houston.html">Google -
houston php</a></td> </tr></table>
Slide: 11
Dynamic test suite• Put all HTML test files in the same directory• Create a new PHP script:
<?php$tests = glob('*.html');?><table> <tr> <td>Meetup presentation</td> </tr><?php foreach ($tests as $filename) { ?> <tr> <td> <a target="testFrame" href="<?php echo $filename; ?>" > <?php echo ucwords(str_replace('.html', '', str_replace('_', ' ',
$filename))); ?> </a> </td> </tr><?php } ?></table>
Slide: 12
Selenium RC• Java server controls
the browser– Windows, Mac OS X,
Linux platforms
• Allows you to write tests in PHP
– Remotely send commands to Java server
• Tightly integrated with PHPUnit!
– Allows you to run UI test suites as regular PHPUnit suites
Slide: 13
Selenium RC requirements• PHPUnit
• PEAR::Testing_Selenium
• Machine to run the actual UI tests from
– We run a VMware image with the latest IE/Firefox, another one with IE6 and Firefox 1.5
Slide: 14
Example of a Test in PHP<?phprequire_once 'SeleniumTestHelper.php';
class LoginTest extends SeleniumTestHelper { public function testAccessToLoginForm() { $this->selenium->open("index.php"); $this->selenium->verifyTextPresent('Having trouble logging in?'); }
public function testFailedLogin() { $this->selenium->open("index.php"); $this->selenium->type("username", "admin"); $this->selenium->type("customer", "2"); $this->selenium->type("password", "blahblah"); $this->selenium->clickAndWait("//input[@value='Log In']"); $this->selenium->verifyTextPresent('Invalid login. Please try again.'); }}?>
Slide: 15
HTML content<!-- more stuff here -->
<table cellspacing='0' cellpadding='0'> <tr> <th>Name</th> </tr> <tr> <td><input type="text" class="textfield" name="username" /></td> </tr> <tr> <th>Customer ID</th> </tr> <tr> <td><input type="text" class="textfield" name="customer" /></td> </tr> <tr> <th>Password</th> </tr> <tr> <td><input type="password" class="textfield" name="password" /></td> </tr> <tr> <td colspan="2"> <input type="image" src="/4/branding.php?param=btn_login" value="Log In" /> <span id="processing" style="display: none;"> <img src="/4/images/icons/spinner.gif" /> <strong>Processing...</strong> </span> </td> </tr></table>
<!-- more stuff here -->
Slide: 16
SeleniumTestHelper<?phprequire_once '../../setup/config.php';require_once 'Testing/Selenium.php';require_once 'PHPUnit2/Framework/TestCase.php';
// ip address of selenium serverif (!defined('APP_SELENIUM_SERVER')) { define('APP_SELENIUM_SERVER', '172.17.0.110');}// which browser to use on this run of the testif (!defined('APP_SELENIUM_BROWSER')) { define('APP_SELENIUM_BROWSER', '*firefox');}
class SeleniumTestHelper extends PHPUnit2_Framework_TestCase{ protected $selenium;
public function setUp() { $this->selenium = new Testing_Selenium(APP_SELENIUM_BROWSER, APP_BASE_URL . APP_RELATIVE_URL, APP_SELENIUM_SERVER); $this->selenium->start(); }
public function tearDown() { $this->selenium->stop(); }}?>
Slide: 17
Targeting browsers• Selenium RC allows for you to run tests in different browsers
– Windows
• Internet Explorer 6.0+
• Firefox 1.5+
– Linux
• Firefox 1.5+
• Opera 9.0.2
• Konqueror 3.5.3
– Mac OS X
• Firefox 1.5+
– Full list at http://selenium-rc.openqa.org/
Slide: 18
How to target browsers• First parameter tells Testing_Selenium what browser to
use
$selenium = new Testing_Selenium(“*firefox”, “http://google.com”, “192.168.1.12”);
• Possible values:– *firefox
– *iexplore
– *opera
– *custom
• more details on this at http://wiki.openqa.org/display/SRC/Selenium+RC+FAQ
• Idea: setup multiple VMware images, one with a specific set of browsers
Slide: 19
RC Test suite<?phpif (!defined('PHPUnit2_MAIN_METHOD')) { define('PHPUnit2_MAIN_METHOD', 'TestSuite::main');}require_once 'SeleniumTestHelper.php';
class TestSuite{ public static function main() { PHPUnit2_TextUI_TestRunner::run(self::suite()); } public static function suite() { $suite = new PHPUnit2_Framework_TestSuite('PHPUnit Framework'); $test_files = glob('*Test.php'); foreach ($test_files as $file) { $suite->addTestFile($file); } return $suite; }} if (PHPUnit2_MAIN_METHOD == 'TestSuite::main') { TestSuite::main();}?>
Slide: 20
Advanced Tests• Testing AJAX requests
– Look for after effects of the AJAX request, such as:
• Icon gets displayed
• Hidden <DIV> is made visible
• XPath support– //div[@id=“recent_traffic_graph”]/img
– //div[4]/div/div/div[1]/div[1]/table/tbody/tr/td[2]/span[4]/a/img
– //table[@id=“table1”]//tr[4]/td[2]
– (//table[@class=“results”])//th[text()=“Price”]/../tr
Slide: 21
Last slideSelenium (IDE, RC, etc)
http://openqa.org
PHPUnithttp://phpunit.de
PEAR::Testing_Seleniumhttp://pear.php.net/package/Testing_Selenium
Recommended booksPHPUnit Pocket Guide
http://oreilly.com/catalog/phpunitpg/
PHPUnit Pocket Guide (online for free)
http://phpunit.de/pocket_guide/
Smarty PHP Template Programming and
Applications (buy it!)
http://smartybook.com