• トップ
  • ブログ一覧
  • 【第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...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background