さて、もう間近にせまった PyCon Apac 2013 ですが、 わたくし パッケージングの今と未来 にて登壇します。
ところで、これ以外にもCFPを提出していまして、没ネタが2つほどあります。
- sqlalchemyの錬金術
- testing pyramid
(´・ω・`)実際のとこ、pyramidの話したかったんですけどねぇ....
Pyramidでのテスト
まずはpylonsprojectのドキュメント Unit Testing Guidelines があります。 これはテストのテクニックではなく作法ですが、テスト内容を明確にするというのが重要な点かなと思います。
Pyramidなところはそんなとこかもしれません。 どこぞのガラパゴスな進化をしたフレームワークと違い、モダンなテストツールをそのまま使えます。(Pythonのフレームワークなのだから当たり前ですけども)
テストケース
pytestやnoseなどはディスカバリー機能を持ってるので、 test_* といった名前の関数でよいですが、伝統的な unittest フレームワークでは、 TestCase クラスを継承します。 フィクスチャとしてよく用いられるダミークラスは pyramid.testing に用意されています。 たとえば、ビュー関数のテストをする場合は pyramid.testing.DummyRequest で request オブジェクトを作ってビュー関数に渡します。
def index(request): return dict(message=request.params['message'])
from pyramid import testing def test_index(): request = testing.DummyRequest(params=dict(message="Hello")) result = index(request) eq_(result, dict(message='Hello'))
ああ、まったく普通のテストですね。
データベース関連のテスト
とりあえず ZODB 使う場合はなにも迷うことはありません。 オブジェクトなので、なにも気にせず単なるクラスとしてテストしましょう。 トランザクションや永続化のようなものは、Persistentクラスやtransactionが面倒を見てくれます。
SQLAlchemy を使う場合もたいていは永続化層のことは考えずにすみます。 zope.sqlalchemyとtransactionによって制御されるので、アプリケーションコードで明示的なcommitなどはしないようにしましょう。 sqlalchemyのsessionから取り出されたオブジェクトは状態が更新された場合に自動でUPDATEを行います。 新規に作成された場合は自動でINSERTされず、sessionに参加させねばなりません。 方法は2通りで、 session.add(obj) で明示的に追加する方法と、既にsessionに参加しているオブジェクトと関連付けします。
pyramidはroute(URLパターンとかそういうやつ)に factory を設定でき、factoryの結果を requestが contextとして持っています。 最初のモデルのロードを factory で行えば、新規オブジェクトは context に追加するだけでよいので、ビュー内でsessionを使う必要はなくなります。
def load_site(request): try: return Site.query.filter(Site.name=='default').first() except NoResultFound: raise HTTPNotFound config.add_route('top', '/', factory=load_site) @view_config(route_name='top', method='POST') def new_document(request): # 入力チェックなど document = Document(**request.params) request.context.documents.append(document) return HTTPFound(request.route_url('document', name=document.name)
load_site のテストはデータベースが必要です。 しかし、 new_document のユニットテストでは、データベースは必要ありません。
機能テスト
pyramidはwsgiフレームワークなので、 WebTest を使ってテストできます。 wsgiミドルウェアを使う場合は、PasteDeployなどを使ってミドルウェア適用済のwsgiアプリをロードしてから、 TestApp を作成しますが、 pyramidは最近あまりwsgiミドルぅエアを使わない傾向にあります。 その場合は単純に、pyramid.config.Configurator.make_wsgi_app を呼ぶだけです。多くの場合、アプリケーションのmain関数を呼ぶだけでしょう。
def test_app(): app = your.app.main({}, **test_settings) app = webtest.TestApp(app) res = app.get('/') res.form['name'] = 'test-document' res.form['data'] = """\ This is First Document ---------------------------------- test """ res = res.form.submit() eq_(res.location, 'http://example.com/test-document') res = app.get(res.location) # ...
まとめ
(´・ω・`)というわけで、pyramid特有となると、context のところくらいしかありませんでした。 餅は餅屋なので、テストツールが提示している書き方をすれば十分ですね。
Comments !