Edited at

Djangoのviewでloginした状態をテストする


テスト対象のコード


view

from django.shortcuts import render

def home(request):
if request.user.is_authenticated:
username = str(request.user)
context = {'username': username}
return render(request, 'dashboard.html', context)
else:
return render(request, 'welcome.html')


上記のviewをテストする。

loginされた状態(request.user.is_authenticatedTrue)か否かで正しく処理が分岐できることを確認したい。


テストツール

viewをテストするには、ダミーのウェブブラウザとして振る舞うdjango.test.Clientを使う。loginされた状態をシミュレートするにはClientのメソッドforce_loginが使える。

公式ドキュメントには、以下の通り記載されている


force_login(user, backend=None)

If your site uses Django's authentication system, you can use the force_login() method to simulate the effect of a user logging into the site. Use this method instead of login() when a test requires a user be logged in and the details of how a user logged in aren't important.


ここのuserをどのように指定すれば良いかパッとは分からず、あれこれ検索した。

その結果、django.contrib.auth.models.Userの提供する、User.objects.create_userを使えば良さそうなことが判明。

また、loginされていない状態をシミュレートするにはClientのメソッドlogoutが使える。


テストコード

ここまで調べた結果を用いて作成したテストコードは以下の通り。ここで、viewであるhomeはURL/は紐付いているものとする。


test

from django.test import TestCase, Client

from django.contrib.auth.models import User

class TestViewsHome(TestCase):

def test_not_authenticated(self):
client = Client()
client.logout()
response = client.get('/')
self.assertFalse('username' in response.context)

def test_authenticated(self):
client = Client()
client.force_login(User.objects.create_user('tester'))
response = client.get('/')
self.assertTrue('username' in response.context)
self.assertEqual(response.context['username'], 'tester')


1件目がloginされていない状態のテスト。応答にはユーザ名(key: username)が含まれていないのが期待。

2件目がloginされた状態のテスト。応答には、loginした時のユーザ名が含まれているのが期待。


テスト実行

以下の通り。2件とも成功。

$ python manage.py test

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

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

カバレッジを参照する。viewを実装したファイルが100%になっているので、request.user.is_authenticatedTrueFalseのどちらのケースもテストできている。

$ coverage run --source='.' manage.py test

$ coverage report
Name Stmts Miss Cover
----------------------------------------------------------
...
apps/views/home.py 7 0 100%


参考にしたサイト

https://docs.djangoproject.com/ja/2.1/topics/testing/tools/

https://docs.djangoproject.com/ja/2.1/topics/auth/default/