views:

48

answers:

2

I'm writing a pair of simple WSGI applications to get a feel for the standard, and I'm to the point where I'd like to test that my applications are working as expected. Now I'm trying to figure out the best way start and stop a server hosting those applications.

My first thought was to start up the SimpleServer from wsgiref in the setUp method and shut it down in the tearDown method. Since serve_forever blocks, I did that work in a separate Thread. Unfortunately, if I use serve_forever to start the server, the secondary thread it's in never dies, and it turns out threading doesn't expose a way to kill a Thread.

Now I'm considering using something like this as my run implementation in the server's Thread:

while keep_going:
    httpd.handle_request()

where keep_going is a variable that I set to True in my setUp and set to False in my tearDown.

Is there a better way? I was hoping to write these apps and tests using just the standard library—the better to understand what I'm abstracting away when I use a lib/framework—but this seems like an awful lot of trouble.

Thanks.

+1  A: 

I don't think SimpleServer was ever intended to run in a thread. You might be better off starting SimpleServer in a separate process, e.g. using the subprocess module in the stdlib. Then, you can spawn/kill the process in your setUp and tearDown methods.

ars
That's a good point, and answers my original question fairly nicely, but after looking at it some more, I think introducing a dependency on WebTest is worth it, at this point.
Hank Gay
+3  A: 

The best way to test WSGI applications is WebTest, which eliminates the need to spawn test servers for your app. Instead, it allows you to do make HTTP requests to your WSGI app as method calls on a TestApp object:

>>> from webtest import TestApp
>>> from myapp import my_wsgi_app
>>> app = TestApp(my_wsgi_app)
>>> res = app.get('/')
>>> res.status
'200 OK'
>>> res.status_int
200
>>> params = {'email': '[email protected]', 'password': 'foo', }
>>> res = app.post('/login/', params)
>>> res.status_int
302

I usually have a base test class that will add a self.app attribute to my test cases that points to a TestApp instance for the WSGI app I'm testing. So my test methods end up looking something like:

def test_index_page(self):
    res = self.app.get('/')
    self.failUnlessEqual(res.status_int, 200)
Will McCutchen
I was trying to avoid libraries, but after looking at the problem some more, I think it's worth it. Thanks.
Hank Gay
In my experience, introducing a dependency (at least for testing) on WebTest is well, well worth it. Good luck!
Will McCutchen