Djangoでテストを理解しようとしてみる

プログラミング

皆さん当たり前のように書かれているテストですが、テストやったことないプログラミング初心者である私からすると、テストが何を行っているかまったくわからないこともあります。そのため、Djangoのテストでわからない部分を調べて忘備録として残しておくことにしました。

ネットやYoutube、書籍で出会ったテストでわかりそうな範囲で調べられることを見つけ次第、追加していきたいと思います。(注意)あくまで素人が推測をもとに書いていることにご注意ください。

そもそもテストとはなんなのか

これはウェブサービスを作ることを前提にした話ですが、作ったシステムが正常に動作するかどうかそのサイトに触れることなく確認できる仕組みのことなのかな、と思っています。そしてテストコードを書き溜めていくと、たくさんのチェックが瞬時にできるようになるので便利、といったこともテストの持つ利点の一つなのでしょう。

assert〜から始まる関数

assertは「断言する・主張する」といった意味の動詞です。ここからassertEqualなどの関数は、「(2つの値が)イコールであることを確認する」といった意味になると推測できます。

下記の表はPython公式ドキュメントのUnittestに掲載されている、一般的に最もよく使用されるメソッドです。これを見れば大体のメソッドはプログラミングでよく使う比較演算子と同じだということがわかります。

メソッド確認事項初出
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) is True
assertFalse(x)bool(x) is False
assertIs(a, b)a is b3.1
assertIsNot(a, b)a is not b3.1
assertIsNone(x)x is None3.1
assertIsNotNone(x)x is not None3.1
assertIn(a, b)a in b3.1
assertNotIn(a, b)a not in b3.1
assertIsInstance(a, b)isinstance(a, b)3.2
assertNotIsInstance(a, b)not isinstance(a, b)3.2

DjangoにおけるTestCaseはPythonのunittestのクラスであるTestCaseを継承して作られたものです。そこにDjango独自のassertTemplateUsedなどの関数を加えているのだと思います。

テストは基本的に比べる対象をある条件をもとに設定し、最後にassert関数で合否判定して問題なければクリア、という流れになるんだと理解してます。このテストを python manage.py test で実行すれば色々な機能が一瞬でチェック出来るようになります。

テスト実例

assertEqual でurlとビューの一致を確認

from django.test import TestCase
from django.urls import resolve

from .views import post_new


class CreatePostTest(TestCase):
    def test_should_resolve_post_new(self):
        found = resolve('/post/new/')
        self.assertEqual(post_new, found.func)

まずresolveが何してるのかさっぱりわかりませんでした。printしてみるとresolve('/post/new/')の引数に対して以下のような値が帰ってくることがわかりました。

ResolverMatch(
    func=post.views.add_post, 
    args=(), kwargs={}, url_name=new, 
    app_names=[], namespaces=[], route=
)

foundに格納されたfuncはどうやら引数のpathに対応するファンクションビューを取得していたようです。url_nameにはurls.pyで設定したnameも取得されています。そしてassertEqualでviewからインポートしたpost_newと取得したfuncが等しいかどうか確認してます。

要するにこれは特定のURLに対してビューとurls.pyのパスが設定されているかどうかを確認するテストだったようです。

assertContains で特定の文字列が含まれているかテスト

    def test_top_page_returns_200_and_expected_title(self):
        response = self.client.get('/')
        self.assertContains(response, "Django", status_code=200)

assertContainsは特定の文字列を含むかどうかチェックします。この場合は「Django」という文字列が含まれているかどうかに加え、status_codeの確認も同時に行っています。

assertTemplateUsed で特定のテンプレートが使われているかテスト

    def test_top_page_uses_expected_template(self):
        response = self.client.get('/')
        self.assertTemplateUsed(response, "posts/top.html")

assertTemplateUsedは指定されたテンプレートがレスポンスのレンダリングに使用されたかどうか確認するものです。この場合は「/」に「posts/top.html」が使用されているかどうかを確認しています。

コメント