[Django]: Django和訳ドキュメント sync to r5922 ==================================================== `Django オンラインドキュメント和訳`_ 更新。 Revision 5881:5922 (2007/08/20). 「mod_python PythonPath」「./manage.py testserver」「testing」についての記述が更新されています。 * `mod_python で Django を動かす`_ * django-admin.py と manage.py - 利用可能なアクション - testserver_ * `Djangoアプリケーションのテスト`_ .. _`mod_python で Django を動かす`: http://michilu.com/django/doc-ja/modpython/ .. _testserver: http://michilu.com/django/doc-ja/django-admin/#testserver-fixture-fixture .. _`Djangoアプリケーションのテスト`: http://michilu.com/django/doc-ja/testing/ .. _`Django オンラインドキュメント和訳`: http://michilu.com/django/doc-ja/index/ 以下、 主な変更です。 `mod_python で Django を動かす`_ --------------------------------------------------- ``PythonPath`` には、アプリケーションから import したいモジュールの各々の 親ディレクトリを入れなければなりません。また、 ``DJANGO_SETTINGS_MODULE`` の親ディレクトリも入れねばなりません。対話シェルを使う場合に Python パスを 設定するのと同じです。何かモジュールを import する際には、Python は必ず ``sys.path`` の各ディレクトリを順に調べ、その下から該当モジュールを import しようと試み、 import に成功するまで探索を続けます。 分かりやすくするために例を挙げましょう。アプリケーションを ``/usr/local/django-apps/`` の下に配置しているとします (例えば、 ``/usr/local/django-apps/weblog/`` のようにです) 。そして、 ``mysite`` プロ ジェクトが ``/var/www/`` 下にあるとしましょう。上の例のように ``DJANGO_SETTINGS_MODULE`` を設定している場合には、 ``PythonPath`` を以下の ように書かねばなりません:: PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path" これで、 ``import weblog`` や ``import mysite.settings`` が正しく動作します。 コード中で ``import blogroll`` していて、 ``blogroll`` が ``weblog/`` ディ レクトリの下にあるようなら、 ``/usr/local/django-apps/weblog/`` も ``PythonPath`` に加えねばなりません。 import したいモジュールの **親ディレクトリ** を Python パスに入れねばならないことに注意してください。 testserver_ [fixture fixture ...] --------------------------------- **開発版の Django で新たに登場した機能です** 指定したフィクスチャを使って、 (``runserver`` と同様に) 開発用サーバを起動 します。 例えば、次のコマンド:: django-admin.py testserver mydata.json を実行すると、以下のようなステップを実行します: 1. `Django アプリケーションのテスト`_ 手順に従って、テストデータベース を生成します。 2. 指定したフィクスチャを使ってテストデータベースに値を入れます (フィク スチャの説明は ``loaddata`` ドキュメントを参照してください)。 3. 生成したテストデータベースを使って (``runserver`` と同様に) 開発サー バを実行します。 ``testserver`` が便利な局面はいくつかあります: * 特定のフィクスチャデータに対するビューの動作を調べるための ユニットテスト を書いている際に、ブラウザでの表示を手動で調べるの に ``testserver`` を使えます。 * Django アプリケーションを開発していて、「無垢の状態の」データベースを 使って操作してみたいとしましょう。データベースを (前述の ``dumpdata`` コマンドを使って) フィクスチャとしてダンプしておき、 ``testserver`` を使って Web アプリケーションを実行すれば、アプリケーション上でどんな 操作を行っても、変更はテストデータベースにしか加えられないので、好き にデータベースを「汚せ」ます。 このサーバはローカルホスト上でデフォルトのポートでしか起動せず、 ``host`` や ``port`` パラメタを受け付けません。 .. _`testing Django applications`: ../testing/ .. _`Django アプリケーションのテスト`: `testing Django applications`_ `Djangoアプリケーションのテスト`_ ============================================ Django でテストを書く方法は主に 2 つあり、それぞれ Python の標準ライブラリ についてくる二つのテストフレームワークに対応しています。フレームワークは以 下の 2 つです: * **doctest** -- 関数やクラスの docstring (ドキュメンテーション文字列) に埋め込まれたテストで、例えば以下のように Python の対話インタプリタ セッションを模した方法で書かれています .. sourcecode:: python def my_func(a_list, idx): """ >>> a = ['larry', 'curly', 'moe'] >>> my_func(a, 0) 'larry' >>> my_func(a, 1) 'curly' """ return a_list[idx] * **ユニットテスト (unit test)** -- 以下の例のように、テストを ``unittest.TestCase``` のサブクラスのメソッドとして表現したものです .. sourcecode:: python import unittest class MyFuncTestCase(unittest.TestCase) def testBasic(self): a = ['larry', 'curly', 'moe'] self.assertEquals(my_func(a, 0), 'larry') self.assertEquals(my_func(a, 1), 'curly') 好みに応じて、どちらのテストを使ってもかまいませんし、両方のテストを組み合 わせてもかまいません。また、後でほんの少しだけ説明しますが、他のテストフレー ムワークを使っても構いません。 例えば、下の関数には、関数の説明の入った docstring があります:: def add_two(num): "引数に指定した数に 2 を加えて返します。" return num + 2 テストはそれ自体素晴らしいドキュメントになることも多いので、テストをそ のまま docstring に入れておけば、ドキュメント化とコードのテストの *両方を* 効率的に行えます。 テストランナは、 Django アプリケーションの中の以下のファイルから doctest を 探して実行します: * ``models.py`` ファイル。モジュールレベル、かつ/またはモデルレベルの doctest を記述します。一般には、アプリケーションレベルの doctest はモ ジュールの docstring として記述し、モデルレベルの docstring はモデル クラスの docstring として記述します。 * アプリケーションディレクトリ、すなわち ``models.py`` の入ったディレク トリ下に置かれた ``tests.py`` という名前のファイル。このファイルは、 モデルに関係しないような doctest を書きたい場合のフックとして使えます。 doctest の文字列は ``models.py`` の全てのオブジェクトに対して記述できますが、 慣習的には、アプリケーションレベルの doctest はモジュールの docstring に、 モデルレベルの doctest は各モデルの docstring に配置します。 モデルテストの場合、テストランナが独自にテストデータベースを作成します。す なわち、データベースに対してアクセスするテスト -- 例えば、モデルインスタン スを生成して保存するようなテスト -- が、実運用のためのデータベースに影響を 及ぼすことはありません。 doctest はいずれも「白紙状態」、すなわち、各モデル のデータベーステーブルが空の状態で実行されます (詳しくは、後述のフィクスチャ の節を参照してください) 。 ユニットテストを書く -------------------- Django の単体テストもまた、doctest と同様、標準ライブラリモジュールの unittest を使います。このモジュールは、 doctest とは違った、 クラスベース のやり方でテストを定義します。 doctest と同様、 Django のテストランナは、以下の二つの場所からユニットテス トを探します: * ``models.py`` ファイル。テストランナはこのモジュールから ``unittest.TestCase`` のサブクラスを探します。 * アプリケーションディレクトリ、すなわち ``models.py`` の入ったディレク トリ下に置かれた ``tests.py`` という名前のファイル。上と同様に、テス トランナはこのモジュールから ``unittest.TestCase`` のサブクラスを探し ます。 開発バージョンの Django には、あるモジュールのテストスイートを定義する方法 をもう一つ提供しています ``models.py`` や ``tests.py`` で ``suite()`` メ ソッドを定義している場合、 Django のテストランナはこのメソッドを使ってテス トスイートを構築します。この仕様は、ユニットテストにおいて 推奨されているテストスイートの構築方法 に従っています。複雑なテストスイー トの構築方法についての詳細は Python のドキュメントを参照してください。 テストの出力を理解する ---------------------- テストを実行すると、まずテストランナ自身の初期化メッセージが表示されます:: Creating test database... Creating table myapp_animal Creating table myapp_mineral Loading 'initial_data' fixtures... No fixtures found. このメッセージは、テストランナがテストデータベースを作成したことを示してい ます。テストデータベースは、空の、何もない状態から作成したデータベースで、 (モデルテストのような) データベースの必要なテストで使われます。 「本番用の」(実運用の) データベースのことは心配いりません。 Django はテスト 用にまったく別のデータベースを作成します。このデータベースの名前は、 ``DATABASE_NAME`` に指定したデータベース名の前に ``test_`` を付けたものにな ります。テストデータベースの名前をデフォルト意外の値にしたければ、 ``TEST_DATABASE_NAME`` 設定を使って名前を指定します。 テスト用に別のデータベースを使うことを除けば、テストランナは設定ファイルの データベースに関する他の設定、 ``DATABASE_ENGINE``, ``DATABASE_USER``, ``DATABASE_HOST`` などをそのまま使います。テストデータベースは ``DATABASE_USER`` の権限で作成されるので、このユーザは新たに生成されたデー タベースを操作する権限を備えていなければなりません。 エラー出力の詳細はこのドキュメントの範囲を超えるので解説はしませんが、ほと んど直感的に理解できる内容のはずです。詳しくは、 Python の ``unittest`` ラ イブラリのドキュメントを参照してください。 スクリプトのリターンコードは失敗したテストや出力のおかしかったテストの総数で す。全てのテストにパスしていれば、リターンコードは 0 です。この仕様は、テス トランナをシェルスクリプト上で動かしたり、テストが成功したかどうかをテスト ランナのレベルで調べたい場合に便利です。 テストにパスしたか否かに関係なく、テストを全て実行し終えると、テストデータ ベースは消去されます。 .. _Testing tools: テスト用のツール ================ Django は、テストを書くときに便利なツールをいくつか提供しています。 .. _The test client: テストクライアント ------------------ テストクライアント (test client) は、簡単なダミーブラウザとして動作する Python のクラスです。テストクライアントを使うと、ビューをテストしたり、 プログラムを使ってDjango で作られたアプリケーションとやりとりできます。 テストクライアントを使ってできることをいくつか挙げましょう: * ある URL に対する GET や POST をシミュレートでき、低水準の HTTP (レスポ ンスヘッダや状態コード) 情報から、ページの内容まで、リクエストに対するレ スポンスの全てを調べられます。 * 特定の URL に対して正しいビューが呼び出されるかどうかを調べられます。 * 特定のリクエストに対して、特定のテンプレートを使ったレンダリングが行わ れ、その際に特定の値が入ったコンテキストが使われているかどうかを調べら れます。 テストクライアントは Twill_ や Selenium_ やその他のブラウザ自動化フレームワー クを置き換えようとするものではありません。 Django のテストクライアントはもっ と別の部分に焦点を当てているのです。すなわち: * 正しいビューが呼び出され、ビューが正しいコンテキストデータを生成してい るかどうかは、 Django のテストクライアントを使って調べてください。 * Twill や Selenium は、 *レンダリング済みの* HTML や、 JavaScript の機能 のような Web ページの *ビヘイビア* のテストに使ってください。 網羅的なテストスイートでは、両方のタイプのテストを組み合わせて使うはずです。 .. _Twill: http://twill.idyll.org/ .. _Selenium: http://www.openqa.org/selenium/ テストの概要と簡単な例 ~~~~~~~~~~~~~~~~~~~~~~ テストクライアントを使うには、 ``django.test.client.Client`` をインスタンス 化して、 Web ページを取得します .. sourcecode:: pyhton >>> from django.test.client import Client >>> c = Client() >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'}) >>> response.status_code 200 >>> response = c.get('/customer/details/') >>> response.content '>> c.get('/login/') は正しいですが、次の呼び出し:: >>> c.get('http://www.example.com/login/') は正しくありません。 Django のプロジェクトから生成されていない Web ページは、テストクライ アントで取得できません。Django 以外の Web ページを取得したければ、 urllib_ や urllib2_ のような Python 標準ライブラリを使ってください。 * テストクライアントは URL の解決に ``ROOT_URLCONF`` に指定された URLconf を使います。 * 上の例は Python の対話インタプリタ中でも動作しますが、一部のテンプレー ト関連の機能などは *テストの実行中だけ* でしか使えません。 というのも、 Django のテストランナは、あるビューでどのテンプレートが ロードされるかを決定するためにちょっとした黒魔術的なコードを使ってい るからです。この黒魔術 (実際には、メモリ上のテンプレートシステムに対 するパッチ) は、テスト実行時にしか適用されません。 .. _urllib: http://docs.python.org/lib/module-urllib.html .. _urllib2: http://docs.python.org/lib/module-urllib2.html .. _Making requests: リクエスト生成 ~~~~~~~~~~~~~~ リクエストの生成には、 ``django.test.client.Client`` クラスを使います。 ``Client`` は引数なしで生成します。:: >>> c = Client() ``Client`` のインスタンスからは、以下のメソッドを呼び出せます: ``get(path, data={})`` ``path`` に対する GET リクエストを行い、 ``Response`` オブジェクトを返 します。 ``Response`` オブジェクトについては後で説明します。 引数 ``data`` は辞書オブジェクトで、キー/値のペアが GET データのペイロー ドの生成に使われます。例えば:: >>> c = Client() >>> c.get('/customers/details/', {'name':'fred', 'age':7}) は、以下のような GET リクエストの送信と同じです:: /customers/details/?name=fred&age=7 ``post(path, data={}, content_type=MULTIPART_CONTENT)`` ``path`` に対する POST リクエストを行い、 ``Response`` オブジェクトを返 します。 引数 ``data`` は辞書オブジェクトで、キー/値のペアが POST データのペイ ロード生成に使われます。例えば:: >>> c = Client() >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'}) は、以下のパス:: /login/ への POST リクエストで、以下の POST データ:: name=fred&passwd=secret を伴います。 ``content_type`` を指定した場合 (例えば XML ペイロードの場合には ``text/xml``)、引数 ``data`` の中身は POST リクエストそのままで送信され、 ``Content-Type`` ヘッダに ``content_type`` の値を使います。 ``content_type`` を指定しなければ、 ``data`` の中身は ``multipart/form-data`` で送信されます。この場合、 ``data`` の中のキー/ 値のペアは、マルチパートメッセージにエンコードされ、 POST データのペイ ロード生成に使われます。 あるキーに対して複数の値を提出 (submit) する場合 (例えば、 ``