• トップ
  • ブログ一覧
  • 【第7回】Djangoで日記アプリを作ろう ~Djangoでテスト実施編~
  • 【第7回】Djangoで日記アプリを作ろう ~Djangoでテスト実施編~

    広告メディア事業部広告メディア事業部
    2021.08.30

    エンジニアになろう!

    【第7回】Djangoで日記アプリを作ろう ~Djangoでテスト実施編~

    前回は、Django テンプレート言語について学びました。

    今回は、Django のテストについて学んでいきましょう!

    この記事では主に、以下の内容を学んでいきます。

    1. テスト実行の流れ
    2. テストの実装方法
    3. テストの出力の意味

    テストの実装方法よりも、Django におけるテストの実行の流れに焦点を当てます。

    そのフローが理解できれば、あとはテストケースを考え、コードに落とし込むだけです。

    Django におけるテストの実装は、Python が標準で提供する、unittest に沿っています。

    なので、そこまで目新しいものはありません。

    前回の記事

    【第6回】Djangoで日記アプリを作ろう ~Djangoテンプレート言語編~2021.06.14【第6回】Djangoで日記アプリを作ろう ~Djangoテンプレート言語編~【第6回】Djangoで日記アプリを作ろう ~Djangoテンプレート言語編~前回は、UpdateView と Del...

    Djnagoにおけるテスト処理の流れ

    それではまず、Django における、テストフローの大枠を掴みましょう!

    細かいところは、後ほど補足をしていきます。

    Django では、テスト用のコマンドを実行すると、下記の流れでテストを実行します。

    1. test.py ファイルより、テストコードを探索
    2. テストで利用するデータベースを作成し、マイグレーションを実施
    3. テストコードを実行
    4. 全テストを実施した後、テスト用データベースを削除(削除せずに残すことも可能)

    test.py ファイルよりテストコードを探索

    まず、test.py というテスト専用のファイルの中から、実行するテストを探索します。

    test.py は、アプリケーションディレクトリの中に配置されています。

    diar ディレクトリの中を、確認してみましょう!

    test.py が配置されていることが、確認できるはずです。

    1diary/
    2├── __init__.py
    3├── admin.py
    4├── apps.py
    5├── forms.py
    6├── migrations
    7│   ├── 0001_initial.py
    8│   └── __init__.py
    9├── models.py
    10├── tests.py # テストケースを実装するファイル
    11├── urls.py
    12└── views.py

    テスト用のデータベースの作成とマイグレーション

    テスト実施に必要な、テスト用データベースを作成しましょう!

    次に、models.py の中身を元に、マイグレーションを実施します。

    基本的にデータベースは、settings.py の DATABASES の設定を参照して、自動的に作成されます。

    つまり、特に何も設定しなくても、テストは実行できるわけですね!

    設定が必要となってくるのは、テスト実行後にデータベースを残しておき、その中身を確認したい場合です。

    この場合には、テスト用の名前を指定すると、後ほどデータベースへの接続がしやすくなります。

    例えば、テスト用データベースの名前を「mytestdb」とする場合、DATABASES 辞書に TEST キーを割り当て、NAME を設定します。

    1DATABASES = {
    2    'default': {
    3        'ENGINE': 'django.db.backends.sqlite3',
    4        'NAME': BASE_DIR / 'db.sqlite3',
    5        'TEST': {
    6            'NAME': 'mytestdb',
    7        }}
    8}

    データベースを残す必要性がないのであれば、TEST キーを付与しなくても構いません。

    TEST キーを付与しない場合には、Django のデフォルト設定に従います。

    このとき、default に設定した NAME に「test_」という接頭語を付けた値が、テスト用データベースの名前になります。

    テストコードを実行

    テストコードの探索とデータベースの作成が済んだので、いよいよテストを実行します。

    なおテストは、django.test モジュールの TestCase を継承したクラスの中で、メソッドとして実装されます。

    当然、1つのテスト用クラスの中に、複数のテスト用メソッドを定義することが可能です。

    例えば、日記モデル用のテストクラスを作成し、その中に、

    1. 日記データの保存と取得をテストするメソッド
    2. 件数の一致を確かめるメソッド

    などを、それぞれ実装していきます。

    テスト用のデータベースの削除

    全てのテストコードの実行が完了すると、テスト用データベースは削除されます。

    データベースを新規作成し、最後に削除を実施するには、データベースの接続ユーザーに「create」と「delete」の権限が付与されている必要があります。

    SQLite3 ではなく、PostgreSQL などの他のデータベースを利用している場合、ユーザーに対して付与されている権限に注意しましょう。

    テストを実装してみよう

    それでは、実際にテストを実装して実行してみましょう。

    diary アプリケーションの中の test.py に、日記モデルに関するテストを実施する、DiaryModelTest クラスを作成します。

    1import datetime
    2from django.test import TestCase
    3from .models import Diary
    4
    5
    6class DiaryModelTests(TestCase):
    7
    8    def test_diary_has_date(self):
    9        """
    10        作成した日記データに日付が付与されているか確認        
    11        """
    12        Diary.objects.create(title='test_title', text='test_text')
    13        actual_diary = Diary.objects.get(title='test_title')
    14        self.assertIsInstance(actual_diary.date, datetime.date)
    15
    16    def test_save_and_retrieve(self):
    17        """
    18        日記データの保存と取得を確認
    19        """
    20        Diary.objects.create(title='test_title', text='test_text')
    21        actual_diary = Diary.objects.get(title='test_title')
    22        self.assertEqual(actual_diary.title, 'test_title')

    このコードのポイントは2つ。

    ポイント1

    1つ目は、DiaryModelTest が TestCase クラスを継承していることです。

    このクラスを継承していないと、テスト用のコードとして見なされません。

    ポイント2

    2つ目は、「test_」から始まるメソッドを定義していることです。

    テスト用メソッドは、必ず「test_」という接頭語を付与します。

    では、このテストを実行してみます。

    以下のコマンドを実行しましょう!

    python3 manage.py test

    以下のような出力が確認できれば、作成した2件のテストが、無事実行できています。

    1Creating test database for alias 'default'...
    2Destroying old test database for alias 'default'...
    3..
    4----------------------------------------------------------------------
    5Ran 2 tests in 0.030s
    6
    7OK
    8Destroying test database for alias 'default'...

    出力を理解しよう

    最後に、テストの出力について、理解を深めましょう。

    先ほどの出力は、「2件のテストが成功した」程度の情報しかありませんでした。

    ですが、出力のレベルを調整すれば、より深い情報を得られます

    以下のコマンドを実行してみましょう。

    python3 manage.py test -v 2

    すると、以下のような出力が得られるはずです。

    1Creating test database for alias 'default' ('mytestdb')...
    2Destroying old test database for alias 'default' ('mytestdb')...
    3Operations to perform:
    4  Synchronize unmigrated apps: bootstrap4, messages, staticfiles, widget_tweaks
    5  Apply all migrations: admin, auth, contenttypes, diary, sessions
    6Synchronizing apps without migrations:
    7  Creating tables...
    8    Running deferred SQL...
    9Running migrations:
    10  Applying contenttypes.0001_initial... OK
    11  Applying auth.0001_initial... OK
    12  Applying admin.0001_initial... OK
    13  Applying admin.0002_logentry_remove_auto_add... OK
    14  Applying admin.0003_logentry_add_action_flag_choices... OK
    15  Applying contenttypes.0002_remove_content_type_name... OK
    16  Applying auth.0002_alter_permission_name_max_length... OK
    17  Applying auth.0003_alter_user_email_max_length... OK
    18  Applying auth.0004_alter_user_username_opts... OK
    19  Applying auth.0005_alter_user_last_login_null... OK
    20  Applying auth.0006_require_contenttypes_0002... OK
    21  Applying auth.0007_alter_validators_add_error_messages... OK
    22  Applying auth.0008_alter_user_username_max_length... OK
    23  Applying auth.0009_alter_user_last_name_max_length... OK
    24  Applying auth.0010_alter_group_name_max_length... OK
    25  Applying auth.0011_update_proxy_permissions... OK
    26  Applying auth.0012_alter_user_first_name_max_length... OK
    27  Applying diary.0001_initial... OK
    28  Applying diary.0002_auto_20201121_1025... OK
    29  Applying diary.0003_remove_diary_deleted_at... OK
    30  Applying diary.0004_auto_20201220_1225... OK
    31  Applying diary.0005_auto_20201220_1227... OK
    32  Applying sessions.0001_initial... OK
    33System check identified no issues (0 silenced).
    34test_diary_has_date (diary.tests.DiaryModelTests)
    35作成した日記データに日付が付与されているか確認 ... ok
    36test_save_and_retrieve (diary.tests.DiaryModelTests)
    37日記データの保存と取得を確認 ... ok
    38
    39----------------------------------------------------------------------
    40Ran 2 tests in 0.058s
    41
    42OK
    43Destroying test database for alias 'default' ('mytestdb')...

    まず、mytestdb というデータベースを作成し、マイグレーションが実行されています。

    その後、DiaryModelTests クラスに定義された、各種テストメソッドが順番に実行されていますね。

    最後に、mytestdb が削除(destroy)され、全ての処理が完了です。

    これは、前の章で学んだ、テストの実施フロー通りです。

    第8回へつづく!

    今回は、Django におけるテストについて学びました!

    次回は、django-allauth というライブラリを用いて、認証機能を実装していきます。

    次回もお楽しみに!

    第8回はこちら!

    【第8回】Djangoで日記アプリを作ろう~認証機能実装編~2021.09.03【第8回】Djangoで日記アプリを作ろう~認証機能実装編~Djangoで日記アプリを作ろう ~認証機能実装編~前回は Django においてテストを実施する方法を学びました。次...

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.07.30Python 特集実装編※最新記事順Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた!P...

    広告メディア事業部

    広告メディア事業部

    おすすめ記事