テストの作成と実行—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/testing/overview
移動先:案内検索

テストの作成と実行

このドキュメントは、2つの主要なセクションに分かれています。 まず、Djangoでテストを作成する方法を説明します。 次に、それらを実行する方法を説明します。

テストを書く

Djangoの単体テストでは、Python標準ライブラリモジュールunittestを使用します。 このモジュールは、クラスベースのアプローチを使用してテストを定義します。

これは、 django.test.TestCase からサブクラス化する例です。これは、トランザクション内で各テストを実行して分離を提供するunittest.TestCaseのサブクラスです。

from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
    def setUp(self):
        Animal.objects.create(name="lion", sound="roar")
        Animal.objects.create(name="cat", sound="meow")

    def test_animals_can_speak(self):
        """Animals that can speak are correctly identified"""
        lion = Animal.objects.get(name="lion")
        cat = Animal.objects.get(name="cat")
        self.assertEqual(lion.speak(), 'The lion says "roar"')
        self.assertEqual(cat.speak(), 'The cat says "meow"')

テストを実行すると、テストユーティリティのデフォルトの動作は、名前が [で始まるファイル内のすべてのテストケース(つまり、unittest.TestCaseのサブクラス)を検索することです。 X179X]、これらのテストケースからテストスイートを自動的に構築し、そのスイートを実行します。

unittestの詳細については、Pythonのドキュメントを参照してください。

テストはどこに置くべきですか?

デフォルトの:djadmin: `startapp` テンプレートは、新しいアプリケーションにtests.pyファイルを作成します。 テストが少ない場合はこれで問題ないかもしれませんが、テストスイートが大きくなるにつれて、テストをtest_models.pytest_views.pytest_forms.pyなど。 好きな組織スキームを自由に選んでください。

Djangoテストランナーを使用した再利用可能なアプリケーションのテストも参照してください。


警告

テストがモデルの作成やクエリなどのデータベースアクセスに依存している場合は、テストクラスをunittest.TestCaseではなく django.test.TestCase のサブクラスとして作成してください。

unittest.TestCaseを使用すると、トランザクションで各テストを実行してデータベースをフラッシュするコストを回避できますが、テストがデータベースと対話する場合、テストランナーが実行する順序に基づいて動作が異なります。 これにより、単体テストは単独で実行すると合格し、スイートで実行すると失敗する単体テストが発生する可能性があります。


テストの実行

テストを作成したら、プロジェクトのmanage.pyユーティリティの:djadmin: `test` コマンドを使用してテストを実行します。

$ ./manage.py test

テスト検出は、単体テストモジュールの組み込みテスト検出に基づいています。 デフォルトでは、これにより、現在の作業ディレクトリの下にある「test * .py」という名前のファイルでテストが検出されます。

./manage.py testに任意の数の「テストラベル」を指定することにより、実行する特定のテストを指定できます。 各テストラベルは、パッケージ、モジュール、TestCaseサブクラス、またはテストメソッドへの完全なPythonドットパスにすることができます。 例えば:

# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests

# Run all the tests found within the 'animals' package
$ ./manage.py test animals

# Run just one test case
$ ./manage.py test animals.tests.AnimalTestCase

# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak

ディレクトリへのパスを指定して、そのディレクトリの下にあるテストを検出することもできます。

$ ./manage.py test animals/

テストファイルの名前がtest*.pyパターンと異なる場合は、-p(または--pattern)オプションを使用してカスタムファイル名パターンマッチを指定できます。

$ ./manage.py test --pattern="tests_*.py"

テストの実行中にCtrl-Cを押すと、テストランナーは現在実行中のテストが完了するのを待ってから、正常に終了します。 正常な終了時に、テストランナーはテストの失敗の詳細を出力し、実行されたテストの数と発生したエラーと失敗の数を報告し、通常どおりテストデータベースを破棄します。 したがって、Ctrl-Cを押すと非常に便利です。一部のテストが予期せず失敗し、完全なテスト実行が完了するのを待たずに失敗の詳細を取得したい場合に注意してください。 。

現在実行中のテストが終了するのを待ちたくない場合は、もう一度Ctrl-Cを押すと、テストの実行はすぐに停止しますが、正常には停止しません。 中断前に実行されたテストの詳細は報告されず、実行によって作成されたテストデータベースは破棄されません。

警告を有効にしてテストする

Python警告を有効にしてテストを実行することをお勧めします:python -Wa manage.py test-Waフラグは、非推奨の警告を表示するようにPythonに指示します。 Djangoは、他の多くのPythonライブラリと同様に、これらの警告を使用して、機能がなくなるときにフラグを立てます。 また、厳密には間違っていないが、より良い実装の恩恵を受ける可能性のあるコード内の領域にフラグを立てる場合もあります。


テストデータベース

データベースを必要とするテスト(つまり、モデルテスト)では、「実際の」(本番)データベースは使用されません。 テスト用に、個別の空白のデータベースが作成されます。

テストが成功したか失敗したかに関係なく、すべてのテストが実行されると、テストデータベースは破棄されます。

test --keepdbオプションを使用すると、テストデータベースが破壊されるのを防ぐことができます。 これにより、実行間でテストデータベースが保持されます。 データベースが存在しない場合は、最初に作成されます。 最新の状態に保つために、移行も適用されます。

前のセクションで説明したように、テストの実行が強制的に中断された場合、テストデータベースは破棄されない可能性があります。 次の実行時に、データベースを再利用するか破棄するかを尋ねられます。 test --noinputオプションを使用して、そのプロンプトを抑制し、データベースを自動的に破棄します。 これは、たとえば、タイムアウトによってテストが中断される可能性がある継続的インテグレーションサーバーでテストを実行する場合に役立ちます。

デフォルトのテストデータベース名は、:setting: `DATABASES` の各:setting:` NAME` の値の前にtest_を付けることで作成されます。 SQLiteを使用する場合、テストはデフォルトでインメモリデータベースを使用します(つまり、データベースはメモリ内に作成され、ファイルシステムを完全にバイパスします!)。 NS :setting: `TEST ` の辞書 :setting: `データベース` テストデータベースを構成するためのいくつかの設定を提供します。 たとえば、別のデータベース名を使用する場合は、次のように指定します。 :setting: `NAME ` の中に :setting: `TEST ` 内の任意のデータベースの辞書 :setting: `データベース`

PostgreSQLでは、:setting: `USER` にも組み込みのpostgresデータベースへの読み取りアクセスが必要です。

別のデータベースを使用する以外に、テストランナーは、設定ファイルにあるのと同じデータベース設定をすべて使用します。 :setting: `ENGINE `:setting: `USER`:setting: `HOST` 、 NS。 テストデータベースは、:setting: `USER` で指定されたユーザーによって作成されるため、指定されたユーザーアカウントに、システム上に新しいデータベースを作成するための十分な権限があることを確認する必要があります。

テストデータベースの文字エンコードをきめ細かく制御するには、 :setting: `CHARSET ` TESTオプション。 MySQLを使用している場合は、 :setting: `COLLATION ` テストデータベースで使用される特定の照合を制御するオプション。 これらおよびその他の詳細設定の詳細については、設定ドキュメントを参照してください。

SQLiteでSQLiteインメモリデータベースを使用している場合、共有キャッシュが有効になっているため、スレッド間でデータベースを共有する機能を備えたテストを作成できます。

テストの実行時に本番データベースからデータを検索しますか?

モジュールのコンパイル時にコードがデータベースにアクセスしようとすると、テストデータベースがセットアップされる前に発生し、予期しない結果が生じる可能性があります。 たとえば、モジュールレベルのコードでデータベースクエリがあり、実際のデータベースが存在する場合、本番データがテストを汚染する可能性があります。 とにかくコードにそのようなインポート時のデータベースクエリを含めるのは悪い考えです-これを行わないようにコードを書き直してください。

これは、 ready()のカスタマイズされた実装にも当てはまります。


テストが実行される順序

すべてのTestCaseコードがクリーンなデータベースで始まることを保証するために、Djangoテストランナーは次の方法でテストを並べ替えます。

  • すべての TestCase サブクラスが最初に実行されます。
  • 次に、他のすべてのDjangoベースのテスト( TransactionTestCase を含む SimpleTestCase に基づくテストケース)が実行され、それらの間で特定の順序が保証または強制されることはありません。
  • 次に、データベースを元の状態に復元せずにデータベースを変更する可能性のある他のunittest.TestCaseテスト(doctestを含む)が実行されます。

ノート

テストの新しい順序により、テストケースの順序に対する予期しない依存関係が明らかになる場合があります。 これは、特定の TransactionTestCase テストによってデータベースに残された状態に依存するdoctestの場合であり、独立して実行できるように更新する必要があります。


test --reverseオプションを使用して、グループ内の実行順序を逆にすることができます。 これは、テストが互いに独立していることを確認するのに役立ちます。


ロールバックエミュレーション

移行で読み込まれる初期データは、TestCaseテストでのみ使用でき、TransactionTestCaseテストでは使用できません。さらに、トランザクションがサポートされているバックエンドでのみ使用できます(最も重要な例外はMyISAMです)。 これは、 LiveServerTestCaseStaticLiveServerTestCase などのTransactionTestCaseに依存するテストにも当てはまります。

Djangoは、TestCaseまたはTransactionTestCaseの本体でserialized_rollbackオプションをTrueに設定することで、テストケースごとにそのデータを再読み込みできますが、これにより、そのテストスイートの速度が約3倍遅くなることに注意してください。

サードパーティのアプリまたはMyISAMに対して開発しているアプリは、これを設定する必要があります。 ただし、一般的には、トランザクションデータベースに対して独自のプロジェクトを開発し、ほとんどのテストでTestCaseを使用する必要があるため、この設定は必要ありません。

通常、最初のシリアル化は非常に高速ですが、このプロセスから一部のアプリを除外したい場合(およびテストの実行をわずかに高速化したい場合)、それらのアプリを:setting: `TEST_NON_SERIALIZED_APPS` に追加できます。

シリアル化されたデータが2回ロードされないようにするには、serialized_rollback=Trueを設定すると、テストデータベースをフラッシュするときに post_migrate 信号が無効になります。


その他の試験条件

構成ファイルの:setting: `DEBUG` 設定の値に関係なく、すべてのDjangoテストは:setting:` DEBUG` = Falseで実行されます。 これは、コードの観察された出力が本番環境で見られるものと一致することを保証するためです。

各テストの後にキャッシュはクリアされません。データベースとは異なり、個別の「テストキャッシュ」はないため、本番環境でテストを実行すると、「manage.pytestfooapp」を実行するとテストのデータをライブシステムのキャッシュに挿入できます。中古。 この動作 :ticket: `変更される可能性があります<11505>` 将来。


テスト出力を理解する

テストを実行すると、テストランナーが準備をしているときに、いくつかのメッセージが表示されます。 コマンドラインのverbosityオプションを使用して、これらのメッセージの詳細レベルを制御できます。

Creating test database...
Creating table myapp_animal
Creating table myapp_mineral

これは、前のセクションで説明したように、テストランナーがテストデータベースを作成していることを示しています。

テストデータベースが作成されると、Djangoがテストを実行します。 すべてがうまくいけば、次のようなものが表示されます。

----------------------------------------------------------------------
Ran 22 tests in 0.221s

OK

ただし、テストが失敗した場合は、失敗したテストの詳細が表示されます。

======================================================================
FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
    self.assertIs(future_poll.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=1)

このエラー出力の完全な説明はこのドキュメントの範囲を超えていますが、かなり直感的です。 詳細については、Pythonのunittestライブラリのドキュメントを参照してください。

テストランナースクリプトのリターンコードは、失敗したテストやエラーのあるテストがいくつあっても1であることに注意してください。 すべてのテストに合格した場合、戻りコードは0です。 この機能は、シェルスクリプトでテストランナースクリプトを使用していて、そのレベルで成功または失敗をテストする必要がある場合に役立ちます。


テストのスピードアップ

テストを並行して実行する

テストが適切に分離されている限り、テストを並行して実行して、マルチコアハードウェアの速度を上げることができます。 test --parallelを参照してください。


パスワードハッシュ

デフォルトのパスワードハッシャーは、設計上かなり遅いです。 テストで多くのユーザーを認証する場合は、カスタム設定ファイルを使用して、:setting: `PASSWORD_HASHERS` 設定をより高速なハッシュアルゴリズムに設定することをお勧めします。

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.MD5PasswordHasher',
]

:setting: `PASSWORD_HASHERS` に、フィクスチャで使用されるハッシュアルゴリズムがある場合は、それも含めることを忘れないでください。


テストデータベースの保存

test --keepdbオプションは、テスト実行間でテストデータベースを保持します。 テストの実行時間を大幅に短縮できる作成アクションと破棄アクションをスキップします。