LoginSignup
254
251

More than 5 years have passed since last update.

[Django] 自動テストについてのまとめ

Last updated at Posted at 2018-09-13

この記事について

PythonのWebアプリケーションフレームワーク「Django」の自動テスト機能についてまとめてみました。

公式サイトのテスト関連ページ

テストを書く場所

manage.py startapp実行時に作成されるtests.pyに記述します。本格的なプロジェクトではtestsをパッケージ化し、その下にtest_XXX.pyという名前でテストを分割するのが一般的です。unittestの規約にのっとり、プロジェクト内のファイル名がtestで始まるファイルが自動テストの対象となります。

テストの実行方法

Djangoでは管理コマンドmanage.pyより自動テストが実行できる。

コマンド

manage.py test

ヘルプ表示

manage.py help test

usage: manage.py test [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS]
                      [--pythonpath PYTHONPATH] [--traceback] [--no-color]
                      [--noinput] [--failfast] [--testrunner TESTRUNNER]
                      [-t TOP_LEVEL] [-p PATTERN] [-k] [-r] [--debug-mode]
                      [-d] [--parallel [N]] [--tag TAGS]
                      [--exclude-tag EXCLUDE_TAGS]
                      [test_label [test_label ...]]

コマンドのオプション

  • -v {0,1,2,3} --verbosity {0,1,2,3}
    実行ログの詳細レベル。レベル3にするとデータベースの変更タイミング等がわかるので、最初の内はこのオプションを使うと理解が早い。

  • -k --keepdb
    自動テストのデフォルト動作では、毎回データベースを再作成する。このオプションを使うと再作成を回避してデータベースを削除せずに残し、次回実行時に再利用する。

  • --settings SETTINGS
    単一の設定ファイル(settings.py)のままだと本番環境、開発環境、自動テスト環境を個別に設定することが難しいので、自動テスト用に個別に設定ファイルを作成するのがベストプラクティスとされている。設定ファイルの分割方法については こちら を参照。データベースの設定方法は後述。

実行範囲の指定

自動テストでは実行単位を設定できる。

# アプリケーション単位
$ ./manage.py test app

# ファイル単位
$ ./manage.py test app.tests

# テストクラス単位
$ ./manage.py test animals.tests.testcase

# メソッド単位
$ ./manage.py test animals.tests.AnimalTestCase.test_can_something

テストのデバッグ方法

pycharmなら自動テストをデバッグモードで実行できる。
参考:Creating Run/Debug Configuration for Tests

テストの動作

処理の流れ

image.png

テストケースクラス

Djangoの自動テストはPython標準のテストモジュールunittest機能を拡張したものである。テストケースはunittest.TestCaseの継承クラスであるdjango.test.TestCaseを継承して記述する。unittest.TestCaseとの違いは以下の通り。

  • テストデータの準備にフィクスチャファイルとデータ準備メソッド(setUpTestData)の2つが使える。各処理はテストケースの実行前に一度だけ実行される。

  • 各テストケースはトランザクションで実行され最終的にロールバックされる。また、各テストメソッドも前述のトランザクション内の子トランザクションとして実行され、メソッドごとにロールバックされる。これによりテストケース、テストメソッド毎の独立性が担保される。

データベースの設定

settings.py上での自動テストのデータベース設定です。開発環境と同じデータベースサーバに別のデータベースを作成することを前提としています。テスト用の設定ファイルを単独で用意する場合は若干違和感のある設定となります。

参考:公式:test データベース

settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': '',  
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
        'TEST': {
            'NAME': 'test_database_name',
        }
    }
}

なお、TEST.NAMEでテスト用データベース名を指定しなかった場合のデフォルトは以下の通りです。

SQLite3の場合  :インメモリデータベースを作成(ファイルは作成されない)
SQLite3以外の場合:メインのデータベース名に「test_」をプレフィックスした名前

注意:デフォルトの動作ではテスト実行の度にデータベースの作成と削除を行います。よって接続ユーザーにデータベースの作成・削除権限が必要です。--keepdbオプションを使って運用するなら読み取り権限だけでOKです。

参考:テストデータをコミットさせる方法

自動テストの開発時やマルチスレッド処理などの特殊なテストを行う際に、データベースをロールバックさせずにコミットさせたい場合があります。そのような時は、「django.test.TestCase」ではなく「unittest.TestCase」を使えばOKです。

Djangoの自動テストの実行対象は「unittest.TestCase」を継承した全てのクラスなので、混在していても大丈夫です。「django.test.TestCase」の継承クラスを実行したあとで、「unittest.TestCase」の継承クラスがまとめて実行されるように順番が制御されています。

テストの書き方・ライブラリの紹介

テストデータの作成

テストデータにはフィクスチャファイルが利用できますが、以下の欠点があります。

  • データの場所がテストコードと違うファイルになり確認しずらい。
  • テキストデータはIDEのサポートが得られにくく管理が大変。

というわけで、テストデータはfactory-boyというライブラリを使い、テストコード上で定義したほうが合理的とされています。factory-boyはテストデータの値を具体値ではなくロジックとして記述することもできるので、複雑な値や構造を持つデータもフィクスチャよりも簡単に作成できます。

参考リンク:

カバレッジの計測

カバレッジ(テストのコード網羅率)の計測には「Coverage.py」を使います。
以前はdjango-nosedjango-coverageといったパッケージが利用されましたが、現在は公式でも「Coverage.py」を推奨しています。

使い方は簡単で、pip install coverageでインストール後、Coverage.py経由でテストを実行して結果ファイルを作成し、レポートをコンソールで表示したり、HTMLで出力させたりします。除外対象の設定等はリンク先を参照してください。

# テスト実行
coverage run --source='.' manage.py test myapp
# レポート出力
coverage report
# HTML出力
coverage html

ユニットテスト

ユニットテストは python の標準的な unittest の書き方を参考にしてください。
とりあえず以下の記事がよく整理されています。

以下の記事も参考になりました。

統合テスト

Djangoのテストフレームワークにはdjango.test.Clientというモジュールが用意されています。これを使うとDjangoアプリケーションに対して仮想的なHTTPリクエストを送信し、レスポンスを受け取るとることができます。Webサーバを起動せずにテストできるので、実際のブラウザを使ったUIテストより低コストです(ただしJavaScriptの実行は不可)。

しかしRuby On Railsで同様の役割を担うCapybaraでは、Djangoのテストクライアントにはない以下の機能があり、テストの自由度に不満がでます。

  • CSSセレクタを使って特定のDOMオブジェクトを取得する。
  • aタグをクリックしてハイパーリンク先に遷移する。

そこでお薦めするのがライブラリdjango-webtestです。
pythonのライブラリwebtestをDjangoで使えるようにしたものです。

これを使うとレスポンスのHTMLページを、スクレイピングで利用されているBeautiful Soupのオブジェクトとして扱えるので、CSSセレクタやaタグのハイパーリンク先への遷移が簡単にできるようになります。

参考:

UIテスト

DjangoでもSeleniumを使ったUIテストが可能です。DjangoではSeleniumを使ったテスト用のモジュールを用意しています。公式サイトを参考にテストケースを作成してください。

以上です。

254
251
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
254
251