.. _guide.testing:

Unit testing
============
Thanks to `WebOb`_, webapp2 is very testable. Testing a handler is a matter
of building a custom ``Request`` object and calling ``get_response()`` on it
passing the WSGI application.

Let's see an example. First define a simple 'Hello world' handler to be
tested::

    import webapp2

    class HelloHandler(webapp2.RequestHandler):
        def get(self):
            self.response.write('Hello, world!')

    app = webapp2.WSGIapplication([('/', HelloHandler)])

    def main():
        app.run()

    if __name__ == '__main__':
        main()

To test if this handler returns the correct ``'Hello, world!'`` response, we
build a request object using ``Request.blank()`` and call ``get_response()``
on it::

    import unittest
    import webapp2

    # from the app main.py
    import main

    class TestHandlers(unittest.TestCase):
       def test_hello(self):
           # Build a request object passing the URI path to be tested.
           # You can also pass headers, query arguments etc.
           request = webapp2.Request.blank('/')
           # Get a response for that request.
           response = request.get_response(main.app)

           # Let's check if the response is correct.
           self.assertEqual(response.status_int, 200)
           self.assertEqual(response.body, 'Hello, world!')

To test different HTTP methods, just change the request object::

    request = webapp2.Request.blank('/')
    request.method = 'POST'
    response = request.get_response(main.app)

    # Our handler doesn't implement post(), so this response will have a
    # status code 405.
    self.assertEqual(response.status_int, 405)


Request.blank()
---------------
``Request.blank(path, environ=None, base_url=None, headers=None, POST=None, **kwargs)``
is a class method that creates a new request object for testing purposes. It
receives the following parameters:

path
  A URI path, urlencoded. The path will become path_info, with any query
  string split off and used.
environ
  An environ dictionary.
base_url
  If defined, wsgi.url_scheme, HTTP_HOST and SCRIPT_NAME will be filled in
  from this value.
headers
  A list of ``(header_name, value)`` tuples for the request headers.
POST
  A dictionary of POST data to be encoded, or a urlencoded string. This is a
  shortcut to set POST data in the environ. When set, the HTTP method is set
  to 'POST' and the CONTENT_TYPE is set to 'application/x-www-form-urlencoded'.
kwargs
  Extra keyword arguments to be passed to ``Request.__init__()``.

All necessary keys will be added to the environ, but the values you pass in
will take precedence.


app.get_response()
------------------
We can also get a response directly from the WSGI application, calling
``app.get_response()``. This is a convenience to test the app. It receives
the same parameters as ``Request.blank()`` to build a request and call the
application, returning the resulting response::

    class HelloHandler(webapp2.RequestHandler):
        def get(self):
            self.response.write('Hello, world!')

    app = webapp2.WSGIapplication([('/', HelloHandler)])

    # Test the app, passing parameters to build a request.
    response = app.get_response('/')
    assert response.status_int == 200
    assert response.body == 'Hello, world!'

Testing handlers could not be easier. Check the `WebOb`_ documentation for more
information about the request and response objects.


Testing App Engine services
---------------------------
If you're using App Engine and need to test an application that uses Datastore,
Memcache or other App Engine services, read
`Local Unit Testing for Python <http://code.google.com/appengine/docs/python/tools/localunittesting.html>`_
in the official documentation. The App Engine SDK provides the module
``google.appengine.ext.testbed`` that can be used to setup all the necessary
service stubs for testing.


.. _WebOb: http://docs.webob.org/