Handler Testing For Python 2

The Local Unit Testing for Python article described how to run unit tests for your application. While unit tests are great for testing the separate units of your code, the integration of those code units is what makes your application run—so integration testing is just as important.

For App Engine applications, request handlers are critical integration points. While a WSGI application routes requests to the right handler, the handler itself processes the request data and generates a response (read more about Request Handlers). Request handlers are normal Python objects like any other function or class, which makes them easy to use in automated tests. But because a WSGI application wraps them like a shell, we will use a similar shell in our tests.

WebTest

For our tests, we will utilize the WebTest framework. WebTest is a library that gives you a simple interface for testing WSGI-based applications and therefore the request handlers. It does so by wrapping a WSGI application in a special test app which can then be used for testing. WebTest allows you to interact with your handlers without a full App Engine environment; you can easily issue requests and modify the request environment. The responses have a test-friendly interface as well. You don't have to use WebTest, but it sure makes your life a lot easier.

Before you can start, install WebTest on your local machine or wherever you intend to run handler tests. Instructions can be found at http://webtest.pythonpaste.org/#installation

Testing a Simple "Hello World" Handler

Let's begin with testing a simple "Hello World!" handler that responds to a user request with a plain-text reply. The handle's response is "Hello World!" and the content type is "text/plain":

import webapp2
import webtest

class HelloWorldHandler(webapp2.RequestHandler):
   def get(self):
       # Create the handler's response "Hello World!" in plain text.
       self.response.headers['Content-Type'] = 'text/plain'
       self.response.out.write('Hello World!')

Next, create the test case and initialize a test application that uses your handler:

...
class AppTest(unittest.TestCase):
    def setUp(self):
        # Create a WSGI application.
        app = webapp2.WSGIApplication([('/', HelloWorldHandler)])
        # Wrap the app with WebTest’s TestApp.
        self.testapp = webtest.TestApp(app)

    # Test the handler.
    def testHelloWorldHandler(self):
        response = self.testapp.get('/')
        self.assertEqual(response.status_int, 200)
        self.assertEqual(response.normal_body, 'Hello World!')
        self.assertEqual(response.content_type, 'text/plain')

As you can see, WebTest allows you to make GET requests with a simple get() call (other request methods have similar methods). The return value is a response object with which you can test the status code, body, content type, and much more—check out the WebTest homepage for a detailed description of all the things you can do.

Creating a Handler Test that Uses an App Engine Service

Now let's have a look at how to test a handler that uses an App Engine service. This means we must now deal with two components that may affect our tests: the handler and the service we are using. As described in the Local Unit Testing for Python article, the best way to deal with services in tests is to use testbed.

The following example uses Memcache, but it is the same in principle for other services like Datastore or Task Queue.

The handler we test caches the given key and value. Notice that we parse both values from the request parameters.

from google.appengine.api import memcache
from google.appengine.ext import testbed
import webapp2
import webtest

class CacheHandler(webapp2.RequestHandler):
  def post(self):
    key = self.request.get('key')
    value = self.request.get('value')
    memcache.set(key, value)

In the test, just like before, first create an application and wrap it with WebTest. Additionally, activate a Testbed instance and take care to deactivate after the test.

...
class AppTest(unittest.TestCase):

  def setUp(self):
    app = webapp2.WSGIApplication([('/cache/', CacheHandler)])
    self.testapp = webtest.TestApp(app)
    self.testbed = testbed.Testbed()
    self.testbed.activate()

  def tearDown(self):
     self.testbed.deactivate()

  def testCacheHandler(self):
    # First define a key and value to be cached.
    key = 'answer'
    value = '42'
    self.testbed.init_memcache_stub()
    params = {'key': key, 'value': value}
    # Then pass those values to the handler.
    response = self.testapp.post('/cache/', params)
    # Finally verify that the passed-in values are actually stored in Memcache.
    self.assertEqual(value, memcache.get(key))

Setting Up a Testing Framework

You can set up a testing framework if you like. Tests for handlers that use WebTest can be executed like your unit tests for App Engine. The only difference is that you need to make sure you have WebTest installed.