blog

Python Logo

Two Things I Missed Functional Testing with WebTest

by

Ian Bicking’s WebTest is a helpful module for running functional tests against a WSGI app. You may already be using it, it’s the suggested way to test Pyramid apps, TurboGears and Google App Engine, and (although I have no experience with this) you can use it with Django (apparently this is a good idea) and Flask. It’s not very complicated but in my haste to get things done I overlooked a couple of its nicest features.

You should read the docs, they’re short and to the point. And there’s this short post that describes how you can use WebTest to test anything HTTP, not just WSGI, that also gives you a very brief introduction to WebTest.

The bits I want to bring to your attention are the form handling, and the integration with pyquery.

Form Handling:

Rather than creating the data to post in the test yourself, you can instead fill out the form on a page and submit it.
If the form has inputs with names ‘name’ and ‘color’ you can do something like this:

response = self.app.get('/something/add.html')
response.form['name'].value = 'some something'
response.form['color'].value = response.form['color'].options[1][0]
response = response.form.submit()

or, in fact the app I’m working on at the moment distinguishes between GET and POST by looking for the specially named submit field in the posted data so I’ve got to submit with the submit button in question, so:

response = response.form.submit('submit_save')

you can check that a form is filled out as you expected when you load a page too:

response = self.app.get('something/edit.html?id=1')
assert('some something' == response.form['name'].value)
assert('blue' == response.form['color'].value)

pyquery:

pyquery allows you to make jQuery queries on XML documents. WebTest has a pyquery helper built in, so you can get the pyquery object from response.pyquery , I spent some frustrated minutes with this before I realized that I needed to remove namespaces before I was going to get any results:

rq = response.pyquery
rq.remove_namespaces()
#

and now you can do things like:

assert(0 == len(rq('div.saved')))
assert(1 == len(rq('div.error')))
assert('Could not Save!' == rq('div.error').text())

which I think is nice and short and hopefully pretty intuitive.

So there you have it, I hope that using the form handling and pyquery helper in WebTest you can make your functional tests simpler to write and easier to read as I did mine.

+ more