【Django(初学者向け)】エラーを未然に防ぐ!自動テストプログラムの基本・書き方を徹底解説!【コピペ可】

Django

(最終更新月:2021年11月)

「作ったアプリがきちんと動作するのか確認したい!」

「エラーをいちいち手作業で確認するのって面倒くさい!」

「でも、test.pyって開いたことない!」

というDjango初学者の方へ向けての記事となります

当記事を通じて、

  1. テストプログラムとは?
  2. テストプログラムの書き方
  3. テストプログラムの実行方法
  4. テストプログラムのコード例

と、テストプラムの基本を徹底的に解説していきます

テストプログラムの作成は足踏みをしているようでもどかしい気持ちもわかりますが、変更を加える度に手作業での確認というのはテストプログラムを作る何倍も大変です

騙されたと思って、一度書けば何度でも実行できる「テストプログラム」をここで始めていきましょう

テストプログラムとは?

テストプログラムとは、

  • コマンド一つ完全自動で実行でき、
  • 個数に限度がなく
  • 何回でも繰り返し使える

エラーチェックのためのプログラムです

アプリ開発が進めば進むほど、

  • 意図したページがきちんと表示されているかどうか?
  • 作成したページが意図したとおりに動作するかどうか?
  • データベースへの保存が正しく行われているかどうか?

など、心配事も増えてくるのは当然です

ただこうした心配をいちいち、手動で試すのはとても時間がかかります

テストプログラムはとっつきにくいのも事実ですが、一度覚えれば超カンタン!

次章以降、解説していきます

テストプログラムの構成

テストしたいapp内のtest.pyTestCaseクラスを記述します

TestCaseクラスは、

  1. 初期設定の関数
  2. エラーチェックのための関数

2種類の関数で構成されています

百聞は一見に如かず

テストプログラムを一緒に作っていきましょう!

TestCaseクラスの書き方

【NippoTestCaseクラスの作成】

「TestCase」をインポートし、継承したクラスを作ります

from django.test import TestCase

class NippoTestCase(TestCase):
    pass

【setUp関数で初期設定を行う】

テストを行いたいモデルクラスのデータを保存しておくのが一般的です

from django.test import TestCase
from nippo.models import NippoModel

class NippoTestCase(TestCase):
    def setUp(self):
        obj = NippoModel(title="testTitle1", content="testContent1")
        obj.save()

日報をデータベースへ一つ保存します

続いて、テスト関数を書いていきますが、ポイントがいくつかありますので次章にて進めていきましょう!

テスト関数の書き方

【書き方のポイント】

  • test_」で始まる関数名とすること
  • self.assertEqual()を使い、動作が正しいかを確認すること

「self.assertEqual(値1, 値2)」で値1と値2が等しい時は正しく動作していると判断されます

【コード例】

日報が正しく保存されているか?」を確認します

def test_saved_single_object(self):
    qs_counter = NippoModel.objects.count()
    self.assertEqual(qs_counter, 1)

【解説】

qs_counter = NippoModel.objects.count()

objects.count()メソッドで、データベースへ保存されているデータの数を変数へ格納しています

「qs_counter」変数には「1」が格納されているべきなので、

self.assertEqual(qs_counter, 1)

とします

実行方法は?

実行方法は、

python manage.py test app名

となります

初期設定関数とテスト関数が書き終わりましたので、実行してみましょう

python manage.py test nippo
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 1 tests in 0.015s

OK
Destroying test database for alias 'default'...

と出てくれば、テストプログラムが正常に動作し、エラーもなく終了したことになります!

作成したテストプログラムのコード

現時点では、上記に加え↓のようなコードにしてます(コピペもご自由にどうぞ!)

from django.test import TestCase
from django.urls import reverse
from nippo.models import NippoModel

class NippoTestCase(TestCase):
    #初期設定
    def setUp(self):
        obj = NippoModel(title="testTitle1", content="testContent1")
        obj.save()

    #日報の作成ができているか
    def test_saved_single_object(self):
        qs_counter = NippoModel.objects.count()
        self.assertEqual(qs_counter, 1)
    
    #queryが存在しない時に、404ページを返すかどうか
    def test_response_404(self):
        detail_url = reverse('nippo-detail', kwargs={"pk": 100})
        detail_response = self.client.get(detail_url)
        update_url = reverse('nippo-update', kwargs={"pk": 100})
        update_response = self.client.get(update_url)
        delete_url = reverse('nippo-delete', kwargs={"pk": 100})
        delete_response = self.client.get(delete_url)
        self.assertEqual(detail_response.status_code, 404)
        self.assertEqual(update_response.status_code, 404)
        self.assertEqual(delete_response.status_code, 404)

    #createページできちんとデータが保存されているか
    def test_create_on_createView(self):
        url = reverse('nippo-create')
        create_data = {"title": "title_from_test", "content": "content_from_test"}
        response = self.client.post(url, create_data)
        qs_counter2 = NippoModel.objects.count()
        self.assertEqual(response.status_code, 302)
        self.assertEqual(qs_counter2, 2)

コメント(#)で示す通り、当記事では3つのエラー確認関数を定義しました

  1. データベースへの保存ができているかどうか
  2. queryが存在しないページへアクセスした際にステータスコード「404」を返すかどうか
  3. createページでPOST送信した時の動作とデータベース内の情報を確認

まずは実行してみましょう!

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.101s

OK
Destroying test database for alias 'default'...

問題無し!

次章で解説します!

【解説】ページアクセスの際のレスポンスを見てみる

test_response_404関数

存在しないpkを入力した際に、ステータスコード「404」が返されているかをチェックしていきます

detail_url = reverse('nippo-detail', kwargs={"pk": 100})

reverseメソッドを使って、ページ名にpkを渡しURLを変数へ格納しています

detail_response = self.client.get(detail_url)

ページへアクセスした際のレスポンスを得る場合は、

self.client.get(ページのURL)

となります

self.assertEqual(detail_response.status_code, 404)

アクセスした際のステータスコードは、

レスポンス.status_code

で取得可能です

404が返されていれば成功!となりますので、上記のような記述となっています

ディテールビュー、アップデートビュー、デリートビュー、3つのビューでの確認をこの関数でまとめて行なっています

【解説】ページ上からPOST送信を確認

test_create_on_createView関数

nippoCreateViewでデータをPOST送信した際にきちんとデータが保存できるか、を確認します

create_data = {"title": "title_from_test", "content": "content_from_test"}

新規保存するデータを辞書型で変数へ格納します

response = self.client.post(url, create_data)

データを保存したい場合は、

self.client.post(ページのURL, 保存したいデータ)

となります

self.assertEqual(response.status_code, 302)
self.assertEqual(qs_counter2, 2)
  1. 保存された場合にきちんとリダイレクト(302)されているかどうか
  2. 保存データの個数が2つになっているか

を確認しています

エラー発生時はどうなるの?

test_create_on_createView関数を最初は下記のとおり記述していました

    def test_create_on_createView(self):
        url = reverse('nippo-create')
        create_data = {"title": "title_from_test", "content": "content_from_test"}
        response = self.client.post(url, create_data)
        self.assertEqual(response.status_code, 201)

実際のコードの「redirect時に返るの302レスポンス」ではなく、「新規保存時に返る201レスポンス」を指定してました

そのときのエラーメッセージはご覧の通りです

FAIL: test_create_on_createView (nippo.tests.NippoTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/.../src/nippo/tests.py", line 33, in test_create_on_createView
    self.assertEqual(response.status_code, 201)
AssertionError: 302 != 201

最後の文章できちんと、指定した201ではなく302だということを説明してくれています

エラー発生の際はこのように間違いを指摘してくれます

おわりに

私自身、「test.pyなんて開いたことない!」というくらいテストプログラムを軽視していた人間でした

ただ、開発をしていると手動でのエラー確認にも限界を感じて、書くようになりました

一度コツをつかめば、頭の良い皆さんであれば、「こんな時は大丈夫?」「こういうときはどうなるの?」など現時点で思い浮かんでいることもあるかもしれません

是非そういう時は思いつくたびにテスト関数を付け足して、より精度の高いテストプログラムを作っていくと後の過程がずいぶんと楽になっていくことと思います

さて、次回は今まで作成したビューをブラッシュアップしていく方法をお伝えしていきます

Bootstrapを使って、見た目を整えていきましょう!

当ブログでは、日報アプリ開発を通じて、Webアプリを一から開発し公開するまでを初学者の方でもわかるようにと記事を連載しています

「Djangoでのアプリ開発を学びたい!」
「Djangoで開発したアプリをWebで公開するにはどうするの?」

という方は必見です!

【Django】チュートリアル|日報アプリの開発から公開まで
Djangoのチュートリアルをお探しですか?具体的に「手を動かして作ってみたい!」という方へ向けて、誰でもできる簡易的な日報アプリの開発を通じて、Djangoの様々な機能に触れていくシリーズとなっています。PythonでWebアプリを作りたい方、必見の記事となります!

タイトルとURLをコピーしました