いろんなもの使ってSBM その1 ゼロ機能リリース

setuptoolsレディなプロジェクトを生成する。

paster create wsgibookmark

色々質問されるが、そこは適宜答える(全部空でもOK)

$ cd wsgibookmark
$ ls
setup.cfg               wsgibookmark
setup.py                wsgibookmark.egg-info

生成されるのはこんな感じ
このうちwsgibookmark.egg-infoは setup.py egg_info で生成できる。
SCMに入れたくないので一旦削除

$ rm -rf wsgibookmark.egg-info/

SCMに登録する。ここではMercurial HG を使ってるが、お好きなように。

$ hg init
$ hg commit -A -m 'start wsgibookmark'

登録したら作業リポジトリを作成

$ cd ..
$ hg clone wsgibookmark wsgibookmark-work
$ cd wsgibookmark-work

テスト環境を作成する。
twill, py.testを利用する。
twillはhttpリクエストを元にした機能テスト
py.testはユニットテストに使用する

$ mkdir -p tests

最初のテストは、単にトップページにアクセスして、bookmarkと表示されることを確認する。

# -*- coding:utf-8 -*-
import os
import twill
from twill.commands import *
from paste.deploy.loadwsgi import loadapp

def setup_module(mod):
    def create_app():
        relative = os.path.join(os.path.dirname(__file__), os.pardir)
        return loadapp("config:test.cfg", relative_to=relative)

    twill.add_wsgi_intercept('localhost', 80, create_app)

def test_top():
    go("http://localhost")
    assert show() == 'bookmark'

setup_moduleはテストモジュール内のテストが実行される前に呼び出される。
この中ではlocalhostの80番ポートにこれからテストするアプリケーションを疑似的にマッピングしている。
これによってtwillコマンド(上の例にあるgoやshow)がlocalhost:80にアクセスしようとすると、マッピングされたアプリケーションにリクエストが転送される。
実際にアプリケーションがlocalhost:80で動くわけではない。
アプリケーションをロードするには、paste.deploy.loadwsgi.loadappを使っている。
loadappにはPasteDeployの設定ファイルを引数とするが、まだその設定ファイルを書いていない。
当然テストは失敗するだろう。

$ touch tests/__init__.py
$ py.test
inserting into sys.path: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/py-0.9.0-py2.5.egg
============================= test process starts ==============================
executable:   /Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python  (2.5.1-final-0)
using py lib: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/py-0.9.0-py2.5.egg/py <rev unknown>

tests/test_application.py[1] F
...
>           OSError: File /Users/aodag/wsgibookmark-work/tests/../test.cfg not found

py.testコマンドは実行したディレクトリ以下にある、test_で始まる名前のpythonモジュールをテストモジュールとして実行する。
予想通りテストは失敗し、その原因もtest.cfgファイルが見つからないことになっている。
設定ファイルを作ろう。
名前はもちろんtest.cfgで置く場所はtestsの1つ上のディレクトリ。つまりプロジェクトディレクトリの直下だね。

[app:main]
paste.app_factory = wsgibookmark:factory

[server:main]
use = egg:PasteScript#wsgiutils
port = 8080

PasteDeployの設定では主に二種類のものを設定する。
アプリケーションとサーバーだ。
アプリケーションはこれから僕らが作るもの。
サーバーはこれを動かす土台だ。
このサーバーはscgiやfcgiのようにhttpdのバックエンドとして動かすものもあればスタンドアローンで使える手軽なものまである。
開発用にはスタンドアローンなものがよいだろう。
PasteScriptのentry_pointにwsgiutilsのスタンドアローンサーバーが設定されているので、それを使う。
アプリケーションには、すでにインストールされているeggからentry_point経由で引っ張ることもできるが、ここはこれから作るものを指定する。
この場合は、ファクトリを設定する。
アプリケーションファクトリの設定は、paste.app_factoryをキーにする。
さて、まだファクトリを書いていないのだから、テストはまだ失敗する。
失敗することを確認したら、ファクトリを書こう。
wsgibookmark:factoryはfrom wsgibookmark import factory で取得できるオブジェクトと考えればいい。
今回の構成では、wsgibookmark/__init__.py 内で factory を定義すればいい。

def app(envrion, start_response):
    start_response("200 OK",
                   [("Content-type", "text/html")])
    return [""]
                   
def factory(global_conf, **local_conf):
    return app

テスト結果

    def test_top():
        go("http://localhost/")
E       assert show() == 'bookmark'
>       assert '' == 'bookmark'
         +  where '' = show()

もちろんまだ、空文字を返しているから上のようなエラーになる。
app関数の戻り値を["bookmark"]にして再度テストを実行してみよう。

tests/test_application.py[1] .

テストが通った!
ひとまずこれをコミットする

$ hg add tests/test_application.py test.cfg
$ hg commit -m 'bookmark application'

実際に動くものを確認してみよう。

$ paster serve test.cfg

アプリケーションを起動できたらブラウザでhttp://localhost:8080にアクセスする。
bookmarkの文字が確認できるはずだ。

参考リンク