Python 2 でのハンドラのテスト

Python のローカル ユニットテストの記事で、アプリケーションの単体テストの実行方法を説明しました。ユニットテストではコードのユニットを個別にテストしますが、統合テストではアプリケーション全体をテストします。統合テストはユニットテストと同様に重要です。

App Engine アプリケーションでは、リクエスト ハンドラが重要な統合ポイントになります。WSGI アプリケーションが適切なハンドラにリクエストを転送する一方、ハンドラはリクエスト データを処理し、レスポンスを生成します(リクエスト ハンドラを参照)。リクエスト ハンドラは通常の Python オブジェクトです。他の関数やクラスと同様に、自動的なテストで簡単に利用できます。ただし、シェルのように WSGI アプリケーションでラッピングされるため、このテストでも類似したシェルを使用します。

WebTest

このテストでは、WebTest フレームワークを使用します。WebTest は、WSGI ベースのアプリケーションやリクエスト ハンドラのテストを行う簡単なインターフェースを提供するライブラリです。テストを行うには、WSGI アプリケーションを特別なテストアプリにラッピングします。WebTest を使用すると、完全な App Engine 環境がなくてもハンドラを操作できます。リクエストの送信やリクエスト環境の変更を簡単に行うことができます。レスポンスには、テストに役立つインターフェースも含まれます。WebTest は必須ではありませんが、テストを簡単に行うことができます。

ローカルマシンまたはハンドラテストを実行する予定のある場所に WebTest をインストールしてから開始してください。詳しい手順については、http://webtest.pythonpaste.org/#installation をご覧ください。

簡単な "Hello World" ハンドラのテスト

では、ユーザー リクエストにプレーン テキストで応答する簡単な "Hello World!" ハンドラのテストを始めましょう。このハンドラのレスポンスは「Hello World!」で、コンテンツ タイプは 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!')

次に、テストケースを作成し、ハンドラを使用するテスト アプリケーションを初期化します。

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

WebTest を使用すると、簡単な get() 呼び出しで GET リクエストを実行できます(別のリクエストのメソッドでも類似した方法を使用します)。返されたレスポンス オブジェクトを使用して、ステータス コード、本文、コンテンツ タイプなどをテストできます。実行可能な操作の詳細については、WebTest のホームページをご覧ください。

App Engine サービスを使用するハンドラテストの作成

では、App Engine サービスを使用するハンドラのテストを行いましょう。このテストでは、ハンドラとサービスの 2 つのコンポーネントを使用します。Python のローカル単体テストの記事にあるように、テストでサービスを扱うには testbed を使用するのが最適な方法です。

次の例では Memcache を使用していますが、基本的にはデータストアやタスクキューなどの他のサービスの場合も同様です。

テスト対象のハンドラは、特定のキーと値をキャッシュします。ここでは、リクエスト パラメータの両方の値を解析しています。

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)

前のテストと同様に、まず、アプリケーションを作成して WebTest でラッピングします。さらに、Testbed インスタンスをアクティブにします。テストが終わったら忘れずに非アクティブ化してください。

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

テスト用フレームワークの設定

必要に応じてテスト用フレームワークを設定できます。WebTest を使用するハンドラのテストは、App Engine のユニットテストと同様に実行できます。ただし、WebTest がインストールされている必要があります。