このサイトについて
Pythonを学ぶ最良の方法とは?
Google App Engineでテスト駆動開発を行うための3つのTips

Google App Engineでテスト駆動開発を行うための3つのTips

Google App Engineの開発ではPythonを使います。GAEを使ったWebアプリの開発でテスト駆動開発を行う際にも,Python的なユニットテストの文脈を活用できます。
ただし,GAEでユニットテストを行うためにはいくつかのツールやトリックが必要です。ここでは,そのテクニックを簡単に紹介します。

 

その1 : NoseGAEを使う

Pythonのテスト用ツールにNoseがあります。このツールは,複数のディレクトリを渡り歩いて,複数のテストコードを一気に実行してくれる便利なツールです。

NoseのプラグインNoseGAEをインストールすることで,GAEアプリのテストを楽に行うことができます。「nose --with-gae」というようにオプション指定をすることでNoseGAEを利用できます。NoseGAEでは,テストコード上でGAEのモジュールやパッケージをインポートするために必要なパスをsys.pathに追加してくれます。


 

その2 : テスト用のstubを使う

GAEのパッケージには,テスト用に使うstubがたくさん登録されています。このstubを登録することで,GAEの認証やDatastoreを使ったWebアプリを手軽にテストできるようになります。
unittestクラスを継承して以下のような基底クラスを使います。setUp()メソッドに以下のようなコードを登録することによって,ダミーの認証モジュールやDatastore用の環境が自動的に構築されます。

import os
import unittest

from handlers import application
from webtest import TestApp

from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_file_stub
from google.appengine.api import mail_stub
from google.appengine.api import urlfetch_stub
from google.appengine.api import user_service_stub
from google.appengine.ext import db, search

from google.appengine.api import users

from models import UserData, UserImage

APP_ID = u'test'
AUTH_DOMAIN = 'gmail.com'
LOGGED_IN_USER = 'test@example.com'

class GAETestBase(unittest.TestCase):

    def setUp(self):

       # API Proxyを登録する
       apiproxy_stub_map.apiproxy =\
                apiproxy_stub_map.APIProxyStubMap()

       # ダミーのDatastoreを登録する
       stub = datastore_file_stub.DatastoreFileStub(APP_ID,'/dev/null',
                                                           '/dev/null')
       apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub)

       # ダミーのユーザ認証用サービスを登録する
       apiproxy_stub_map.apiproxy.RegisterStub(
                                 'user', user_service_stub.UserServiceStub())
       os.environ['AUTH_DOMAIN'] = AUTH_DOMAIN
       os.environ['USER_EMAIL'] = LOGGED_IN_USER

       # ダミーのurlfetchを登録
       apiproxy_stub_map.apiproxy.RegisterStub(
                         'urlfetch', urlfetch_stub.URLFetchServiceStub())

       # ダミーのメール送信サービスを登録
       apiproxy_stub_map.apiproxy.RegisterStub(
                         'mail', mail_stub.MailServiceStub())


このクラスを継承してユニットテスト用のクラスを作ります。テスト用のメソッドが呼ばれる前にstartUp()メソッドが呼ばれ,自動的にstubを登録し,テスト用の環境を構築してくれます。

 

class UserTest(M6Base):

    def test_some_function(self):
        # テストコードを書く!


 

テストコードでは,usersやDatastore,GQLのクエリなどを自由に活用することができます。


その3 : WebTestを使う

GAEアプリケーションの実体はwgsiアプリケーションです。WebTest(http://pypi.python.org/pypi/WebTest/)はwsgiアプリをテストするための便利なツールです。テストの課程でダミーのリクエストを送ったりするには,このWebTestを使うと楽ちんです。
テストコードでは,まず以下のようにしてアプリケーションのインスタンスを作ります。


from webtest import TestApp
app = TestApp(application)

 

GETリクエストを送るには,appインスタンスを使って以下のようにします。


app.get('/path/to/requetst')

POSTリクエストで送るにはpost()メソッドを使います。引数に辞書を渡してデータを送ります。


app.post('/path/to/request', {'foo':'hoge', 'bar', 'hage'})

オマケ

Noseはテスト用のツールであるだけでなく,テスト用の便利関数をたくさん内蔵しています。テストが通らなかったときに,渡した値をログに表示してくれるので,assert文を書くよりずっと楽です。

from nose.tools import *

# 引数(式)が偽の解きにassert
assert_true(some_condition)

# 2つの引数(式)が等しくなかったらassert
assert_equal(a, b)


ドキュメント(英文)
Google App Engineは某社の案件(この時点でGAEを使える会社ってあんまりないけどね!)で絶賛活用中なんですが,とても面白いですね〜。正式リリースが待ち遠しいです:-)。

 


2010-08-27 04:48