Firstly down Selenium RC and from the zip file copy /selenium-python-client-driver-1.0.1/selenium.py and place that in your test directory. This is the library file for allowing Python to talk to the Selenium Grid Hub. Another file that you will need is XML Test Runner. This XML Test Runner is an extension to Python's built in Unit Testing that will output jUnit style XML reports that Hudson can read and display the results for.
The test suite I am setting out below will run the tests in parallel and has provisions to do more in the future. It can be set up in the future to run different sets of tests, run all the tests in different browsers and has some early examples of external configuration and common functions.
So in my Selenium job in Hudson I changed the execute shell to be: ./Swrunner.py and said that the published jUnit test results are *.xml. I also had to chmod the working directory to give the Hudson user permission to write out the jUnit results out to this directory. One other change I made was to stop using the Selenium Grid Hudson plugin as that seem to have issues with running more tests than there were available nodes, so I fixed this by like in Part 1 of just running the Hub from the command line and that seems to work well.
You can either see the scripts below to download them in a zip file.
selenium.py - from Selenium RC zip file
SWconfig.py:
'''
Created on 17 July 2010
@author: Dave
These are connection details
Idea from: http://viewvc.svn.mozilla.org/vc/projects/sumo/tests/frontend/python_tests/vars.py?view=markup
'''
class connectionParameters:
server = '172.24.128.200'
port = 4444
baseurl = 'http://shihadwiki.com'
page_load_timeout = 600000
browser = '*firefox'
SWfunctions.py:
'''
Created on 17 July 2010
@author: Dave
These are some generic function examples for running ShihadWiki.com
'''
def openSite(sel, page_load_timeout):
sel.open("/wiki/Main_Page")
sel.wait_for_page_to_load(page_load_timeout)
def clickMenu(sel, link, page_load_timeout):
sel.click('//li[@id=\'n-%s\']/a' % (link))
sel.wait_for_page_to_load(page_load_timeout)
SWrunner.py:
#!/usr/bin/python
'''
Created on 17 July 2010
@author: Dave
This is the test runner to run all the tests
Idea from: http://viewvc.svn.mozilla.org/vc/projects/sumo/tests/frontend/python_tests/suite_sumo.py?view=markup
Idea from: http://saucelabs.com/blog/index.php/2009/09/running-your-selenium-tests-in-parallel-python/
'''
import SWfunctions
from SWconfig import connectionParameters
from SWtestList import testList
import sys
from subprocess import Popen
args = sys.argv
type = None
if len(args) < 2:
type = 'smoke'
else:
type = args[1]
tests = []
if type == 'smoke':
tests = testList.smoke_list
elif type == 'full':
tests = testList.full_list
browsers = []
browsers.append('*firefox')
processes = []
for browser in browsers:
vars = connectionParameters
for test in tests:
processes.append(Popen('python %s %s %s %s %s %s' % (test, vars.server, vars.port, browser, vars.baseurl, vars.page_load_timeout), shell = True))
for process in processes:
process.wait()
SWtestList.py:
'''
Created on 17 July 2010
@author: Dave
These are the tests to execute
Idea from: http://viewvc.svn.mozilla.org/vc/projects/sumo/tests/frontend/python_tests/tests.py?view=markup
'''
class testList():
smoke_list = []
#smoke_list.append(file-name.py)
smoke_list.append('test-gigs.py')
smoke_list.append('test-songs.py')
smoke_list.append('test-discography.py')
full_list = []
full_list.extend(smoke_list)
test-discography.py:
from selenium import selenium
import unittest, time, re
import sys
import SWfunctions
from xmlrunner import *
host = None
port = None
broswer = None
baseurl = None
page_load_timeout = None
class test_discography(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium(host, port, broswer, baseurl)
self.selenium.start()
self.selenium.set_timeout(page_load_timeout)
def test_discography(self):
sel = self.selenium
SWfunctions.openSite(sel, page_load_timeout)
SWfunctions.clickMenu(sel, 'Discography', page_load_timeout)
self.assertEqual("Discography - Shihad Wiki", sel.get_title())
try: self.failUnless(sel.is_text_present("Discogarphy"))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == '__main__':
args = sys.argv
host = args[1]
port = args[2]
broswer = args[3]
baseurl = args[4]
page_load_timeout = args[5]
suite = unittest.TestSuite()
suite.addTest(test_discography('test_discography'))
#suite.addTest(test_songs.test_songs)
#unittest.TextTestRunner().run(suite)
runner = XMLTestRunner(file('results_test_discography_%s.xml' % (broswer), "w"))
runner.run(suite)
test-gigs.py
from selenium import selenium
import unittest, time, re
import sys
import SWfunctions
from xmlrunner import *
host = None
port = None
broswer = None
baseurl = None
page_load_timeout = None
class test_gigs(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium(host, port, broswer, baseurl)
self.selenium.start()
self.selenium.set_timeout(page_load_timeout)
def test_gigs(self):
sel = self.selenium
SWfunctions.openSite(sel, page_load_timeout)
SWfunctions.clickMenu(sel, 'Gigs', page_load_timeout)
self.assertEqual("Gigs - Shihad Wiki", sel.get_title())
try: self.failUnless(sel.is_text_present("Gigs"))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == '__main__':
args = sys.argv
host = args[1]
port = args[2]
broswer = args[3]
baseurl = args[4]
page_load_timeout = args[5]
suite = unittest.TestSuite()
suite.addTest(test_gigs('test_gigs'))
#unittest.TextTestRunner().run(suite)
#runner = xmlrunner.XmlTestRunner(sys.stdout)
runner = XMLTestRunner(file('results_test_gigs_%s.xml' % (broswer), "w"))
runner.run(suite)
test-songs.py
from selenium import selenium
import unittest, time, re
import sys
import SWfunctions
from xmlrunner import *
host = None
port = None
broswer = None
baseurl = None
page_load_timeout = None
class test_songs(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium(host, port, broswer, baseurl)
self.selenium.start()
self.selenium.set_timeout(page_load_timeout)
def test_songs(self):
sel = self.selenium
SWfunctions.openSite(sel, page_load_timeout)
SWfunctions.clickMenu(sel, 'Songs', page_load_timeout)
self.assertEqual("Category:Songs - Shihad Wiki", sel.get_title())
try: self.failUnless(sel.is_text_present("Songs"))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == '__main__':
args = sys.argv
host = args[1]
port = args[2]
broswer = args[3]
baseurl = args[4]
page_load_timeout = args[5]
suite = unittest.TestSuite()
suite.addTest(test_songs('test_songs'))
#suite.addTest(test_songs.test_songs)
#unittest.TextTestRunner().run(suite)
runner = XMLTestRunner(file('results_test_songs_%s.xml' % (broswer), "w"))
runner.run(suite)
xmlrunner.py - from http://www.rittau.org/python/
The Series:
- Part 1 - Getting Started
- Part 2 - Getting Hudson to run the tests
- Part 3 - Integrating Selenium Python tests with Hudson and having them run in parallel
- Part 4 - How to get Multiple Browsers and Operating Systems working
Upcoming ideas for the series:
- Putting the test suite in SVN and running from there
2 comments:
wow. i am impressed. keep it up.
Great Posts!!
I've been having a hard time getting the steps to work on Windows, but I was able to resolve one of the issues:
Traceback (most recent call last):
File "test-songs.py", line 45, in
runner = XMLTestRunner(file('results_test_songs_%s.xml' % (broswer), "w"))
IOError: [Errno 22] invalid mode ('w') or filename: 'results_test_songs_*firefox.xml'
Windows doesn't like the "*" in the name, so to fix this you have to go to each file that is having the error, such as test-songs.py , and change from
runner = XMLTestRunner(file('results_test_songs_%s.xml' % (broswer), "w"))
to:
runner = XMLTestRunner(file('results_test_songs_%s.xml' % (broswer[1:-1]), "w"))
I will post my updates on other issues I faced as well.
Post a Comment