Handler-Tests für Python 2

Im Artikel Testen lokaler Einheiten für Python wurde beschrieben, wie Einheitentests für Ihre Anwendung ausgeführt werden. Diese Einheitentests eignen sich hervorragend zum Testen der einzelnen Einheiten von Code, aber erst durch die Integration dieser Codeeinheiten wird die Ausführung von Anwendungen möglich. Daher sind Integrationstests ebenso wichtig.

Für App Engine-Anwendungen sind Request-Handler wichtige Integrationspunkte. Requests werden von einer WSGI-Anwendung an den richtigen Handler weitergeleitet, der Handler selbst verarbeitet die Request-Daten und generiert eine Antwort (weitere Informationen finden Sie unter Request-Handler). Request-Handler sind normale Python-Objekte wie jede andere Funktion oder Klasse, sodass sie in automatisierten Tests einfach zu verwenden sind. Da sie aber von einer WSGI-Anwendung wie von einer Shell umschlossen werden, verwenden wir in unseren Tests eine ähnliche Shell.

WebTest

Für unsere Tests verwenden wir das Framework WebTest. WebTest ist eine Bibliothek, die Ihnen eine einfache Schnittstelle zum Testen von WSGI-basierten Anwendungen und damit der Request-Handler bietet. Dazu wird eine WSGI-Anwendung in eine spezielle Testanwendung eingebunden, die dann zum Testen verwendet werden kann. Mit WebTest können Sie ohne eine vollständige App Engine-Umgebung mit Handlern interagieren. Sie können auf einfache Weise Requests senden und die Request-Umgebung ändern. Auch für die Antworten wird eine testfreundliche Schnittstelle bereitgestellt. Sie müssen WebTest nicht verwenden, aber es macht Ihnen das Leben wesentlich einfacher.

Bevor Sie beginnen, installieren Sie WebTest auf Ihrem lokalen Rechner oder auf einem anderen Computer, auf dem Sie Handler-Tests ausführen möchten. Eine Anleitung finden Sie unter http://webtest.pythonpaste.org/#installation.

Einfachen "Hello World"-Handler testen

Beginnen wir mit dem Testen eines einfachen "Hello World!"-Handlers, bei dem mit einer Nur-Text-Antwort auf einen Nutzer-Request reagiert wird. Die Antwort des Handlers lautet "Hello World!" und der Inhaltstyp ist "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!')

Erstellen Sie als Nächstes den Testfall und initialisieren Sie eine Testanwendung, in der der Handler verwendet wird:

...
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')

Wie Sie sehen, können Sie GET-Requests mit WebTest mit einem einfachen get()-Aufruf erstellen (andere Request-Methoden bieten ähnliche Methoden). Der Rückgabewert ist ein Antwortobjekt, mit dem Sie den Statuscode, den Textkörper, den Inhaltstyp und vieles mehr testen können. Auf der WebTest-Startseite finden Sie eine ausführliche Beschreibung aller möglichen Aktionen.

Handlertest erstellen, der einen App Engine-Dienst verwendet

Betrachten wir nun, wie Sie einen Handler testen, der einen App Engine-Dienst verwendet. Wir müssen uns hier also mit zwei Komponenten befassen, die Einfluss auf unsere Tests haben können: dem Handler und dem Dienst, den wir verwenden. Wie im Artikel Tests lokaler Einheiten für Python erläutert, wird am besten testbed verwendet, wenn bei Tests Dienste eine Rolle spielen.

Im folgenden Beispiel wird Memcache verwendet, das Prinzip ist jedoch bei anderen Diensten wie Datastore oder Task Queue dasselbe.

Der getestete Handler speichert den angegebenen Schlüssel und Wert im Cache. Beachten Sie, dass wir beide Werte aus den Request-Parametern parsen.

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 dem Test erstellen Sie genau wie zuvor zuerst eine Anwendung und umschließen sie mit WebTest. Aktivieren Sie zusätzlich eine Testbed-Instanz, die Sie nach dem Test auf jeden Fall wieder deaktivieren müssen.

...
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))

Test-Framework einrichten

Wenn Sie möchten, können Sie ein Test-Framework einrichten. Tests für Handler, bei denen WebTest verwendet wird, können wie Einheitentests für App Engine ausgeführt werden. Der einzige Unterschied besteht darin, dass WebTest installiert sein muss.