Note: this was originally posted on the Pivotal Labs blog.
Selenium RC Fu is a fantastic system for testing Ruby On Rails applications. It is the blending of xUnit testing with selenium. Selenium is an amazing system that operates your browser as if a human were sitting there moving the mouse, pressing buttons and keys.
Selenium RC Fu is also a remarkable example of the power of open source. It’s Selenium remotely controlled by rails and ruby. You can learn more about it by viewing the slides for Full-stack webapp testing with Selenium and Rails presented by my colleagues Alex Chaffee and Brian Takita at the SDForum Silicon Valley Ruby Conference.
Now that you are excited about Selenium RC Fu, by law I must inform you that this wonderful testing tool comes with some costs. First, this is the daisy cutter of testing — problems will be detected, but it won’t be too specific about those problems. A failed selenium test will likely only tell you some expected text was not present on the page — you have to do some digging to discover the real problem.
It’s also slow. To be fair, a lot of software is running to do this testing.
So use selenium testing sparingly. A good strategy is to restrict selenium testing to “happy path” testing. These happy path tests become a compliment to other more focused and faster unit and integration tests.
Getting Started With Selenium RC Fu
Selenium RC Fu is hosted at rubyforge.org in the “pivotal.rb” project. It’s not well documented and a little hard to find. The primary documentation is the README File.
Step 1 is to add it to your project:
script/plugin install svn://rubyforge.org/var/svn/pivotalrb/seleniumrc_fu/trunk
Building Your Tests
Create your tests in
app/tests/selenium. The basic structure mirrors the other test types:
require File.dirname(__FILE__) + "/selenium_helper" class HappyPathsTest < MyProject::SeleniumTestCase def test_nav_bar ... end def test_about ... end # more tests end
HappyPathsTest extends something called
MyProject::SeleniumTestCase. Selenium RC Fu provides a sample selenium helper file that suggests this convention for name spacing your tests.
For the happy paths tests I simply wanted to go to a page and know that the page loads. A pattern I learned from my colleague Shifra is:
- Pick something you know is on the target page, but not on the current page. Let’s call it ‘evidence’. Assert that evidence is not present on the current page.
- go to the target page
- assert the evidence is present on the target page.
This process insures that you are moving about as you expect. Here’s an example from my project:
def test_tasks ... assert_element_not_present "xpath=//h1&91;text()='The Daily Planet']" click_and_wait "link=The Daily Planet" assert_element_present "xpath=//h1[text()='The Daily Planet']" ... end
I repeated this simple pattern for every path.
Here are the functions and assertions I used in my tests:
type locator, text
assert_equal value1, value2
Many of the functions require a ‘locator’ argument. This needs to identify a single element on the page. Often the name or id of an element is sufficient, but you may need to use an XPath. Check the docs for more information on element locators.
These functions were sufficient for me. Look for more in
Selenium RC Fu comes with some rake commands too (from
rake -T selenium):
rake selenium:restart_servant # Stop and start the selenium servant (the server that launches browsers) on localhost rake selenium:run_server # Run the selenium servant in the foreground rake selenium:server # Run the selenium remote-control server rake selenium:start_servant # Start the selenium servant (the server that launches browsers) on localhost rake selenium:stop_servant # Stop the selenium servant (the server that launches browsers) on localhost rake selenium:test # Run a selenium test file (default test/selenium/selenium_suite) rake selenium:test_with_server_started # Run the selenium tests in Firefox
Running Your Tests
You can run your selenium tests individually or as part of a suite. Selenium RC Fu comes with a suite script in the
vendor/plugins/seleniumnrc_fu/sample directory. Drop that in your
The selenium server must be running before running individual tests. You can start the server with the rake command
rake selenium:server. Once the server is running you run your tests from the command line or via the suite.
You can also run the suite with the command
rake selenium:test. This command is smart enough to start the server if it’s not already running. However, when the server is started by this mechanism its a little more work to stop it. You can stop the server with a simple ^c if it was started via the
rake selenium:server command.
Make It So
That’s really all you need to build your tests but here are few more things that may help.
A site diagram is handy for building your happy paths tests. There will be a lot of paths through the site and marking the paths on the diagram as you visit them is an easy way to track your progress. On the diagram you need to indicate both pages and the paths to those pages.
The later is really important. It’s the paths that you will be testing with your happy path selenium testing. Often there are buttons, links, or other controls such as check boxes that may touch the server and reload the current page, or just update the current page via ajax. Be sure to add these to your navigation diagram.
Here’s the diagram I used for my site.
You can code your tests by hand using Selenium RC Fu functions but it’s easier if you use Selenium IDE. This is a Firefox plugin that records your activity. That activity is available in various selenium dialects and can be pasted into your tests. Unfortunately, it does not have output for Selenium RC Fu. Nonetheless I still found it useful. I simply clicked through my application while Selenium IDE was recording, pasted the resulting selenium commands into my tests, then converted those commands to equivalent Selenium RC Fu commands. For example:
Output from Selenium IDE:
@selenium.click "link=My Account" @selenium.wait_for_page_to_load "30000" assert @selenium.is_text_present("Update Account")
click_and_wait "link=My Account" assert_text_present "Update Account"
Your selenium tests will be exercising your application just like standard unit or integration tests. These tests require data and there are a variety of techniques to make data available to your tests. Building your happy path tests is easier if you have fixture data and that fixture data is loaded in your development environment via
rake db:fixtures:load. If you use fixture scenarious, it is handy to have a scenario for selenium testing, which you would load with something like
rake db:scenario:load SCENARIO=selenium.
With your fixtures loaded in your development environment you can see exactly what is present during testing and the selenium IDE will record exactly what is played back by selenium.
Usually Selenium IDE can assign a locator that simply works but there are times when it can’t or won’t. Using XPath Checker you can right click on an element and it will display an XPath to that element. You can also experiment with varitions and XPath Checker will list all of the elements on the page that can be identified by that XPath.
That’s it. Let me know how it goes.