Unit testing with cookies (mocking a request)

2,293 views
Skip to first unread message

Peter Bengtsson

unread,
Sep 28, 2010, 9:16:12 AM9/28/10
to Tornado Web Server
Hi, I'm interested in unit testing my handlers AND to do integration
test with AsyncHTTPTestCase.

I used the testing.py module from tornado which works great for both
unit testing handlers as well as HTTP integration tests.

# In app.py
class HomeHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello %s" % self.get_secure_cookie('name'))


# In test_app.py
class ApplicationTest(AsyncHTTPTestCase, LogTrapTestCase):

def get_db(self):
return self._app.con[self._app.database_name]

def get_app(self):
return app.Application(database_name='test')

# integration test
def test_homepage_fetch(self):
self.http_client.fetch(self.get_url('/'), self.stop)
response = self.wait()
self.assertTrue('Hello unknown' in response.body)
# Now I want to try again but with a cookie mocked but don't
know how


# handler unit test
def test_homepage_handler(self):
handler = app.HomeHandler(self._app, REQUEST??)
handler.get()
self.assertTrue('Hello unknown' in RESPONSE.read()??)



So, can someone tell me how to mock the integration test by forcing in
a particular cookie there?
And can someone tell me how to mock a request and response so that I
can control the cookies before the get() method is run.

Ben Darnell

unread,
Sep 28, 2010, 6:11:16 PM9/28/10
to python-...@googlegroups.com
On Tue, Sep 28, 2010 at 6:16 AM, Peter Bengtsson <pet...@gmail.com> wrote:
> Hi, I'm interested in unit testing my handlers AND to do integration
> test with AsyncHTTPTestCase.
>
> I used the testing.py module from tornado which works great for both
> unit testing handlers as well as HTTP integration tests.
>
> # In app.py
> class HomeHandler(tornado.web.RequestHandler):
>    def get(self):
>        self.write("Hello %s" % self.get_secure_cookie('name'))
>
>
> # In test_app.py
> class ApplicationTest(AsyncHTTPTestCase, LogTrapTestCase):
>
>    def get_db(self):
>        return self._app.con[self._app.database_name]
>
>    def get_app(self):
>        return app.Application(database_name='test')
>
>    # integration test
>    def test_homepage_fetch(self):
>        self.http_client.fetch(self.get_url('/'), self.stop)
>        response = self.wait()
>        self.assertTrue('Hello unknown' in response.body)
>        # Now I want to try again but with a cookie mocked but don't
> know how

Read response.headers["Set-Cookie"] and use it to construct an
appropriate Cookie header to pass in on the next request. (maybe use
the cookielib or Cookie modules from the standard library to do the
parsing? haven't looked into it myself)

>
>
>    # handler unit test
>    def test_homepage_handler(self):
>        handler = app.HomeHandler(self._app, REQUEST??)
>        handler.get()
>        self.assertTrue('Hello unknown' in RESPONSE.read()??)

We don't really support this style of testing; I recommend just
sticking with AsyncHTTPTestCase.fetch() instead of trying to call
handler.get/post() directly.

-Ben

Brian Jones

unread,
Sep 30, 2010, 11:06:06 PM9/30/10
to python-...@googlegroups.com
On Tue, Sep 28, 2010 at 6:11 PM, Ben Darnell <b...@bendarnell.com> wrote:
On Tue, Sep 28, 2010 at 6:16 AM, Peter Bengtsson <pet...@gmail.com> wrote:
>    # handler unit test
>    def test_homepage_handler(self):
>        handler = app.HomeHandler(self._app, REQUEST??)
>        handler.get()
>        self.assertTrue('Hello unknown' in RESPONSE.read()??)

Tornado doesn't really need to support this, depending on the actual needs of your test case. In my work, I want to isolate the methods within my RequestHandler object completely to perform unit testing, and then in later testing stages I link things together a bit more for functional and integration testing. When I say "isolate" I mean that the only code that gets touched during the test is code you wrote yourself for the purpose of the test, and the method you want to test. In the case of get(), that means you don't even really want your handler's __init__() to run, because that implies mocking out an app and a request object, and then you're down the rabbit hole. Here's one way you can isolate get() (in this very basic simple example): 

class TestMainHandler(myproject.handlers.MainHandler):
    def __init__(self):
        self.chunk = ''

    def write(self, chunk):
        self.chunk = chunk 

class TestStuff(unittest.TestCase):
    def setUp(self):
        self.handler = TestMainHandler()

    def test_get(self):
        self.handler.get()
        self.assertEquals(self.handler.chunk, 'Hello, world')

So, in the tornado.web.RequestHandler source, the write() method actually writes content to a buffer a chunk at a time. You've replaced the buffer with self.chunk here, written to it, and tested the output. In a more complex example you'd probably have more parsing to do to come up with things to compare in assertEquals. It could get complex, but I do like that this isolates the test for the get() method from tests for the rest of the handler class, and the larger Tornado system. 

hth. 
brian



We don't really support this style of testing; I recommend just
sticking with AsyncHTTPTestCase.fetch() instead of trying to call
handler.get/post() directly.

-Ben

>
>
>
> So, can someone tell me how to mock the integration test by forcing in
> a particular cookie there?
> And can someone tell me how to mock a request and response so that I
> can control the cookies before the get() method is run.



--
Brian K. Jones
My Blog          http://www.protocolostomy.com
Follow me      http://twitter.com/bkjones
Reply all
Reply to author
Forward
0 new messages