dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[GAE] Google App Engine の単体テストにpytestを使う(with zc.buildout)

タイトル通り、Google App Engineユニットテストpytest を使うため
以前勉強した zc.buildout でセットアップしてみた時のメモ。

GAE のライブラリを zc.buildout で管理する方法については以下の記事をご覧ください。

buildout を設定する

とりあえず pytest を動かすだけなら以下だけでよさそう。

buildout.cfg

[buildout]
parts =
  python-dev

bin-directory = bin
eggs-directory = .buildout-eggs
parts-directory = .buildout-parts
develop-eggs-directory = .buildout-develop-eggs

newest = false
unzip = true

[python-dev]
recipe = zc.recipe.egg
eggs =
  mock==1.0.0
  pytest
  pytest-xdist
  pytest-cache
  pytest-capturelog
  pytest-cov
  pytest-timeout
scripts =
  py.test=pytest

設定ファイルを保存したら、buildout を実行します。

$ ./bin/buildout
Unused options for buildout: 'unzip'.
Installing python-dev.
Generated script '/Users/*****/bin/pytest'.

bin ディレクトリの下に pytest というコマンドが生成されています。

bin/pytest を実行する

では、適当なテストファイルを作成して実行してみましょう。
ディレクトリ構成は django アプリケーションを元にしているため、以下のようになっています。

[アプリケーションの root]
├── bin
│   └── pytest
├── pytest_sample
│   ├── models.py
│   └── tests.py
│
├── app.yaml
├── settings.py
├── urls.py
...

models.py に適当な ndb のモデルを定義し、tests.py ではそれを利用する簡単なテストです。

models.py

# -*- coding: utf-8 -*-
from google.appengine.ext import ndb

class Account(ndb.Model):
    author = ndb.UserProperty()
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

tests.py

# -*- coding: utf-8 -*-
import pytest

from .models import Account

class TestAccount(object):

    def test_obj(self):
        obj = Account()
        assert obj

では、これで pytest を実行します。

$ ./bin/pytest pytest_sample/tests.py
=============================== ERRORS ==============================
____________ ERROR collecting pytest_sample/tests.py ____________
pytest_sample/tests.py:4: in <module>
    from google.appengine.ext import ndb
E   ImportError: No module named google.appengine.ext
====================== 1 error in 0.04 seconds ======================

あれ、google_appengine のモジュールが読み込まれてない...

エラーの原因は?

何か色々調べたけど、どうやら /usr/local/google_appengine へのパスを通すことで解決した様子。

以下を .zshrc に追記。

.zshrc

PYTHONPATH="/usr/local/google_appengine:/usr/local/google_appengine/lib/django-1.5:$PYTHONPATH"
export PYTHONPATH

注) /usr/local/google_appengine/lib/django-1.5 は今回は関係ないと思います。私の環境で django を使っているだけです

これで再度 pytest を実行

$ source ~/.zshrc
$ ./bin/pytest pytest_sample/tests.py

pytest_sample/tests.py .
================= 1 passed in 0.37 seconds =================

おーよかった。
とりあえずテストが走るところまではできました。

TODO

とりあえず pytest の実行までこぎつけましたが、実際に Google App Engine のデータストア絡みのテストを書こうとすると
色々とはまりどころが多いです。(というか、まだはまっていて整理できていない。。。)

それはまた後日。

リファレンス

No module named ... エラーの原因を調査してた時に、dev_appserver.fix_sys_path() を使うと書いていた記事

http://tell-k.hatenablog.com/entry/2012/01/12/001830

これはテストを実行するスクリプトを用意して、そちらを実行するというもの。
ただ、使っているのは unittest 。

http://d.hatena.ne.jp/ishidamakot/20110406/1302103904