Unit testing web.py/WSGI applications

112 views
Skip to first unread message

W. Martin Borgert

unread,
Jun 8, 2013, 8:04:25 AM6/8/13
to we...@googlegroups.com
Hi,

currently I'm testing my web.py application using twill. I'm not
happy with twill, however, mainly because I have to reference
forms and form fields by number (1st, 2nd, ...). I would like to
reference by id, name etc.

I'm looking into two alternatives to twill: webtest and webunit.
Does anybody have experiences with either framework?
Or another one?

To me, it is important that:
- I don't need to start a web server, i.e. testing uses the
WSGI interface directly
- I don't need a web browser (such as with selenium)

With twill, this works fine, but with the forementioned
limitation.

TIA and cheers

Tomas Schertel

unread,
Jun 8, 2013, 10:40:50 PM6/8/13
to we...@googlegroups.com

Maybe you can use web.browser:

>>> import web
>>> web.browser.__doc__
'Browser to test web applications.\n(from web.py)\n'

W. Martin Borgert

unread,
Jun 10, 2013, 4:59:32 AM6/10/13
to we...@googlegroups.com, Tomas Schertel
Quoting "Tomas Schertel" <tsch...@gmail.com>:
> Maybe you can use web.browser:
>
>>>> import web
>>>> web.browser.__doc__
> 'Browser to test web applications.\n(from web.py)\n'

web.browser looks really nice, thanks for the hint!

Unfortunately, web.browser is not documented extensively.
E.g. it is not clear to me how to (un)check a checkbox or
select a radio button.

Does anybody know how to do this? TIA!

Pradeep Banavara

unread,
Jun 10, 2013, 5:05:02 AM6/10/13
to we...@googlegroups.com
have you tried tools such as Selenium ?




--
You received this message because you are subscribed to the Google Groups "web.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webpy+unsubscribe@googlegroups.com.
To post to this group, send email to we...@googlegroups.com.
Visit this group at http://groups.google.com/group/webpy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.



Anand Chitipothu

unread,
Jun 10, 2013, 5:06:47 AM6/10/13
to webpy, Tomas Schertel
The browser object has a select_form method. That selects a form to work on and the the browser can be used like a dictionary to set values of the form. 

b.select_form(index=1)

And now b works like a client form object. 

b['name'] = 'foo'

I don't remember how checkboxes behave. You can get access to the client form object from b.form.

See client form documentation to see how that works.


Anand



On Mon, Jun 10, 2013 at 2:29 PM, W. Martin Borgert <deb...@debian.org> wrote:
--
You received this message because you are subscribed to the Google Groups "web.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webpy+unsubscribe@googlegroups.com.
To post to this group, send email to we...@googlegroups.com.
Visit this group at http://groups.google.com/group/webpy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


W. Martin Borgert

unread,
Jun 10, 2013, 5:24:47 AM6/10/13
to we...@googlegroups.com, Pradeep Banavara
Quoting "Pradeep Banavara" <prad...@gmail.com>:
> have you tried tools such as Selenium ?

Yes, I'm using Selenium for many tests, i.e. SST (selenium-simple-test,
http://testutils.org/sst/). It is, however, more difficult (but possible)
to set up Selenium tests automatically for a build server than e.g. with
twill or web.browser. For that reason, I'm using both frameworks.

W. Martin Borgert

unread,
Jun 10, 2013, 7:55:02 AM6/10/13
to we...@googlegroups.com, Anand Chitipothu, webpy, Tomas Schertel
Quoting "Anand Chitipothu" <anand...@gmail.com>:
> I don't remember how checkboxes behave. You can get access to the client
> form object from b.form.
>
> See client form documentation to see how that works.
>
> http://wwwsearch.sourceforge.net/old/ClientForm/

OK, I'm still struggling with this...

Another problem I have: I can't really logout from my web.py
application with web.browser. I even cleared the cookiejar of
web.browser explicitly ("browser.cookiejar.clear()"), but no
success.

Cheers

PS: Maybe web.browser should be on the todo list for the future
of web.py? Either it needs work on the documenation (examples
for typical scenarios, including different form elements,
cookie handling etc.) or it should be marked deprecated.

Tomas Schertel

unread,
Jun 10, 2013, 10:06:44 AM6/10/13
to we...@googlegroups.com, Anand Chitipothu, Tomas Schertel
I think using web.browser as a tester is a good thing. It should be improved.

About your logout problem: what method are you using to logout? POST or GET?

W. Martin Borgert

unread,
Jun 10, 2013, 10:56:22 AM6/10/13
to we...@googlegroups.com, Tomas Schertel, Anand Chitipothu
Quoting "Tomas Schertel" <tsch...@gmail.com>:
> I think using web.browser as a tester is a good thing. It should be
> improved.

I suggest, somebody understanding web.browser, should document it
with some nice examples. Maybe this is sufficient.

Also, maybe it could be an optional or external component in respect
to web.py. This would make web.browser attractive to people not (yet)
using web.py. E.g. probably thousands of small web apps don't use any
framework, just Python and wsgi, but are in need of a small test tool.

> About your logout problem: what method are you using to logout? POST or GET?

Unfortunately still the latter. (Yes, this needs a change, but...)

Tomas Schertel

unread,
Jun 10, 2013, 11:00:04 AM6/10/13
to we...@googlegroups.com, Tomas Schertel, Anand Chitipothu

Couldn't make a GET call to you logout page?

W. Martin Borgert

unread,
Jun 10, 2013, 11:10:17 AM6/10/13
to we...@googlegroups.com, Tomas Schertel, Anand Chitipothu
Quoting "Tomas Schertel" <tsch...@gmail.com>:
> On Monday, 10 June 2013 11:56:22 UTC-3, Nickname wrote:
>> Quoting "Tomas Schertel" <tsch...@gmail.com <javascript:>>:
>> > About your logout problem: what method are you using to logout? POST or
>> GET?
>>
>> Unfortunately still the latter. (Yes, this needs a change, but...)
>>
>>
> Couldn't make a GET call to you logout page?

Sorry, I don't quite understand the question.

What I'm doing is:

browser.open('/logout/')
browser.open('/')

but I'm still logged in.

Matteo Landi

unread,
Jun 10, 2013, 3:32:40 PM6/10/13
to we...@googlegroups.com
On Sun, Jun 9, 2013 at 4:40 AM, Tomas Schertel <tsch...@gmail.com> wrote:
> On Saturday, 8 June 2013 09:04:25 UTC-3, Nickname wrote:
>>
>> Hi,
>>
>> currently I'm testing my web.py application using twill. I'm not
>> happy with twill, however, mainly because I have to reference
>> forms and form fields by number (1st, 2nd, ...). I would like to
>> reference by id, name etc.
>>
>> I'm looking into two alternatives to twill: webtest and webunit.
>> Does anybody have experiences with either framework?
>> Or another one?

I played with webtest and I have to say that it is very powerful: I
used it to test the endpoints of a REST API (with standard HTTP status
codes, file uploads and stuff like that..) and it worked like a charm.
Sometimes the documentation leaves something to be desired but in the
end it is I have always found the solution to my problems.


My two cents,

Matteo

>>
>> To me, it is important that:
>> - I don't need to start a web server, i.e. testing uses the
>> WSGI interface directly
>> - I don't need a web browser (such as with selenium)
>>
>> With twill, this works fine, but with the forementioned
>> limitation.
>>
>> TIA and cheers
>
>
> Maybe you can use web.browser:
>
>>>> import web
>>>> web.browser.__doc__
> 'Browser to test web applications.\n(from web.py)\n'
>
> --
> You received this message because you are subscribed to the Google Groups
> "web.py" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to webpy+un...@googlegroups.com.

W. Martin Borgert

unread,
Jun 10, 2013, 3:39:16 PM6/10/13
to we...@googlegroups.com
On 2013-06-10 21:32, Matteo Landi wrote:
> I played with webtest and I have to say that it is very powerful: I
> used it to test the endpoints of a REST API (with standard HTTP status
> codes, file uploads and stuff like that..) and it worked like a charm.
> Sometimes the documentation leaves something to be desired but in the
> end it is I have always found the solution to my problems.

Maybe you found a solution for this problem: I took a look into
webtest and found that I can reference forms via their id or
their positional number (like twill). I would have to reference
a form in some cases by their name, or better by arbitrary xpath
expressions. Is this possible with webtest?

(We go a little bit off-topic in respect to web.py itself, OTOH
most web.py developers have to unittest their apps...)

Tomas Schertel

unread,
Jun 10, 2013, 9:53:20 PM6/10/13
to we...@googlegroups.com, Tomas Schertel, Anand Chitipothu
 Would you mind sharing your logout code?

W. Martin Borgert

unread,
Jun 11, 2013, 2:35:33 AM6/11/13
to we...@googlegroups.com, Tomas Schertel
On 2013-06-10 18:53, Tomas Schertel wrote:
> Would you mind sharing your logout code?

It's as short as:

class Logout:
def GET(self):
try:
MyApp.session.kill()
except KeyError:
log.error("tried to end unknown session")
raise web.found(u'/')

Cheers

Matteo Landi

unread,
Jun 11, 2013, 3:35:13 AM6/11/13
to we...@googlegroups.com
On Mon, Jun 10, 2013 at 9:39 PM, W. Martin Borgert <deb...@debian.org> wrote:
> On 2013-06-10 21:32, Matteo Landi wrote:
>> I played with webtest and I have to say that it is very powerful: I
>> used it to test the endpoints of a REST API (with standard HTTP status
>> codes, file uploads and stuff like that..) and it worked like a charm.
>> Sometimes the documentation leaves something to be desired but in the
>> end it is I have always found the solution to my problems.
>
> Maybe you found a solution for this problem: I took a look into
> webtest and found that I can reference forms via their id or
> their positional number (like twill). I would have to reference
> a form in some cases by their name, or better by arbitrary xpath
> expressions. Is this possible with webtest?

It should be possible [1]; have a look at the following snippet:

>>> from webtest import TestRequest
>>> from webtest import TestResponse
>>> res = TestResponse(content_type='text/html', body=b'''
... <html><body><div id="content">hey!</div></body>''')
>>> res.request = TestRequest.blank('/')
>>> res.html

<html><body><div id="content">hey!</div></body></html>
>>> res.html.__class__
<class 'BeautifulSoup.BeautifulSoup'>
>>> res.lxml
<Element html at ...>
>>> res.lxml.xpath('//body/div')[0].text
'hey!'

Does this solve your issue?


Cheers,

Matteo

[1] http://webtest.pythonpaste.org/en/1.4.3/

>
> (We go a little bit off-topic in respect to web.py itself, OTOH
> most web.py developers have to unittest their apps...)
>

W. Martin Borgert

unread,
Jun 11, 2013, 3:48:09 AM6/11/13
to we...@googlegroups.com
On 2013-06-11 09:35, Matteo Landi wrote:
> It should be possible [1]; have a look at the following snippet:
>
> >>> from webtest import TestRequest
> >>> from webtest import TestResponse
> >>> res = TestResponse(content_type='text/html', body=b'''
> ... <html><body><div id="content">hey!</div></body>''')
> >>> res.request = TestRequest.blank('/')
> >>> res.html
>
> <html><body><div id="content">hey!</div></body></html>
> >>> res.html.__class__
> <class 'BeautifulSoup.BeautifulSoup'>
> >>> res.lxml
> <Element html at ...>
> >>> res.lxml.xpath('//body/div')[0].text
> 'hey!'
>
> Does this solve your issue?

Not sure: How would I fill in a form field found with the xpath
expression and submit the form? This is the missing bit for me.

TIA!

Matteo Landi

unread,
Jun 11, 2013, 4:37:55 AM6/11/13
to we...@googlegroups.com
I cannot try it right now, but I imagine that you can use xpath to get
the desired form:

>>> form = res.lxml.xpath('//body/div/form')[0]

At this point, with the form in hand you can do whatever you want:
fill fields, submit, etc. Does this make sense?


Matteo

>
> TIA!

W. Martin Borgert

unread,
Jun 11, 2013, 6:22:07 AM6/11/13
to we...@googlegroups.com, Matteo Landi
Quoting "Matteo Landi" <mat...@matteolandi.net>:
> I cannot try it right now, but I imagine that you can use xpath to get
> the desired form:
>
>>>> form = res.lxml.xpath('//body/div/form')[0]
>
> At this point, with the form in hand you can do whatever you want:
> fill fields, submit, etc. Does this make sense?

Almost :~) I fiddled a little bit with it and came up with this:


# in my app, forms have unique names, but seldomly ids
def get_form_by_name(resp, name):
return webtest.Form(resp, lxml.etree.tostring(
resp.lxml.xpath("//form[@name='%s']" % name)[0]))

resp = app.get("/")
form = get_form_by_name(resp, "myform")
form["field"] = "whatever"
resp = form.submit()


Seems to work... Many thanks for the help!

Reply all
Reply to author
Forward
0 new messages