Introduction to Functional Web Testing With Twill & Selenium

Part 2 :: Selenium Gotchas :: Quick Tour of the Selenium API

Synopsis

Powerful but a pain in the butt.

Selenium Gotchas
[Minutes 153 - 165]

Quick Tour of Selenium API
 

I'm not going to discourage you, but I'm going to be honest, the 'selenium.py' module is a mess. Don't believe me, open up the docs and take a look for yourself. (The docs come with the package and are in the python client/docs dir; they're also online here.)

I, personally, don't think this is the fault of the Selenium project. You have to consider that you need to pack in client driving behavior into a extensible module; if anything, I think it speaks to how complicated our web browsers and applications have become.

Here are a couple of nuggets of wisdom that might save you some time:

  • xPath is tough, don't let anyone fool you.
  • xPath in IE is broken.
  • wait_for_page_to_load() is a great function.
  • Grokking locaters is pretty key when you start thinking how a browser behaves.

A good place to look for hints is to check out the tests that selenium ships with:

              [pzerbinos] selenium-python-client-driver-1.0-beta-2 $ ls -p | grep 'test'
              selenium_test_suite.py
              selenium_test_suite_headless.py
              test_ajax_jsf.py
              test_default_server.py
              test_google.py
              test_i18n.py
            

If you check them out, you'll see that they're unittest-style tests, but they'll still serve as a useful example. You should also feel free to run them (just type 'nosetests'!), watch them fail, and try to figure out what happened.

Below are a few basic commands you're going to need to know; check the docs for the rest:

command description example
open(self, url) pass in the URL you want to open as a string open('http://www.google.com/')
type(self, locator, value) sets the value of an input field; often the locator is the name of the input field type('q', 'help me')
click(self, locator) click on a button, checkbox, link, radio button. Again, locator is the [html] name of the thing you're clicking on. click('btnG')
key_press(self, locator, keySequence) simulates a user pressing a key. If this fails, try key_down() followed by key_up(). The docs say those two are equivalent to key_press(), but that's not always true. The keySequence is the javascript key code; find a list of them here. key_press(input_id, 97)

One thing that's frustrating about doing prototyping in the IDE and then trying to script it out is that the function names are often quite different. For example, in the IDE, you haveverifyTextPresent and verifyTextNotPresent, and in python you've got is_text_present(). Not the biggest deal in the world, but definitely something to keep in mind.

Got it? Good. Let's write a test. We'll start with some non-ajaxy stuff so you can get the hang of it. Go ahead and create 'test_our_thing.py'; all we're going to do is make sure the title's what we think it is.

              from selenium import selenium
              from nose.tools import eq_
              
              def test_our_thing():
                  s = selenium("localhost", 4444, "*firefox", "http://127.0.0.1/")
                  s.start()
                  s.open("http://127.0.0.1/index.html")
                  eq_("Introduction to Functional Web Testing With Twill & Selenium", s.get_title())
                  s.close()
                  s.stop()
            

Okay, there you go. A few things to notice about that test. First, the import from nose.tools of eq_. That's equivalent to unittest's assertEqual (which is what you'll see in the tests that ship with selenium). You can, of course, just do an assert.

There's also a lot more boilerplate here than there is with the twill tests; before you can start actually testing anything, you have to instantiate an instance of selenium and start up the server.

You also have to shut the server down, and if you don't wrap your tests in try/except clauses or account for it in some other way, the server will not stop if the test fails. (In the test above, for example, Firefox will just stay open if that assertion fails.)

Otherwise, it's totally easy... right?

Fluid 960 Grid System, created by Stephen Bau, based on the 960 Grid System by Nathan Smith. Released under the GPL/ MIT Licenses.