Nidelven IT - All about Python, Zope & Plone - and Open Source!

Here you'll find issues related to our services. Mostly about Python, Zope and Plone, as well as hosting-related issues.

"Keeping IT real"

Older entries

Atom - Subscribe - Categories
Previous | Next

Functional testing - there's no excuse now

I've developed things for a long time, but never really got bit by the testing part of development. But now, after having some bugs arise at an inopportune moment (software running on several major version of other software), I decided that it was time to get serious about quality control and thus testing.

I looked around here and there and eventually found the zope.testbrowser package which promised to be able to work with any website, so OK. And it does. I know this blog entry is also published on so bear with me, even if it says zope.testbrowser it doesn't depend on a big part of the zope framework, just little bits of it.

This was on an old account, so I had to unpack and build Python 2.7 first, and then download and run ( from ).

OK, so I did that and then ran easy_install to install zope.testbrowser in the current directory:

PYTHONPATH=. ./usr/bin/easy_install --install-dir=. zope.testbrowser

And then created a in the current directory like this:

from zope.testbrowser.browser import Browser

and then ran Python with

PYTHONPATH=. ./usr/bin/python -i

To have it include the current directory in sys.path. Running Python this way runs the script and then lets you play with the b variable.

An interactive session can be like this:

# Get the first (and only form)
>>> b.getForm()
<zope.testbrowser.browser.Form object at 0x8599a6c>
# _ is the last returned value - you know this
>>> form=_
# Get the search_string input element
>>> form.getControl(name='search_string')
<Control name='search_string' type='text'>
>>> search=_
# Look at what we can get
>>> dir(search)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__implemented__', '__init__', '__module__', '__new__', '__providedBy__', '__provides__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_browser_counter', '_enable_setattr_errors', 'add_file', 'browser', 'clear', 'disabled', 'mech_control', 'mech_form', 'multiple', 'name', 'type', 'value']
# Pretend we're entering python as a user in a browser
>>> search.value = 'python'
# And submit the form
>>> form.submit()
>>> dir(b)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__implemented__', '__init__', '__module__', '__new__', '__providedBy__', '__provides__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_changed', '_clickSubmit', '_contents', '_counter', '_enable_setattr_errors', '_findByLabel', '_findByName', '_get_all_controls', '_start_timer', '_stop_timer', 'addHeader', 'contents', 'cookies', 'follow', 'getControl', 'getForm', 'getLink', 'goBack', 'handleErrors', 'headers', 'isHtml', 'lastRequestPystones', 'lastRequestSeconds', 'mech_browser', 'open', 'post', 'raiseHttpErrors', 'reload', 'timer', 'title', 'url']
# Here we're checking that some of the contents of
# the returned page is correct, ironically for this
# example search doesn't work properly, but that's
# what you can expect when you don't run a lot of
# tests. :)
>>> 'Search results for <em>python</em>.' in b.contents

That's about as simple as it can get IMO. :)

Reading through the zope.testbrowser.interfaces gives a good explanation of different methods and properties that are available, so just go read that if this is intesting.

[Permalink] [By morphex] [Python-only or > 0.5 Python related (Atom feed)] [2012 10 Oct 20:24 GMT+2]



By: Benji York

I'm glad you found testbrowser useful. I've considered renaming it so people don't mistakenly think that it only works with Zope. Maybe I will rename it if I ever do a 2.0.

If you have any questions about testbrowser, I would be happy to answer them.

Excellent tips!

By: Patricio Páez

Thanks for your post. I got to know about zope.testbrowser which extends mechanize, and also learned to use PYTHONPATH=. in the command line, and something=_ in IDLE to instantiate something and then refer to it. I am already using both tricks in my everyday Python!

Add comment (text format)


A passphrase is required to comment on this weblog. It is required to make sure that bots aren't doing automatic spamming. It is: nit is the best!.