デバッグとテストについてのレポート


Pythonを用いたデバッグとテストを、Part3のTODO課題で作ったブログアプリで試してみます。

アプリのコードのURLは、
https://github.com/maeclamar/todo-part3
です。

Pdbを用いたデバッグ

Pdbを用いてデバッグしてみます。
Pdbの使い方は、こちらの記事を参考にしました。
views.pyを開き、コードにPdbのインポート文を追加します。

blogs/views.py
def detail(request, blog_id):
    import pdb; pdb.set_trace() #追加
    blog = Blog.objects.get(id=blog_id)
    comments = Comment.objects.filter(post=blog)

    if request.method == "POST":
        form = forms.CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.post = blog
            comment.author = request.user
            comment.save()
#            form = forms.CommentForm() #いったんコメントアウト

この状態でいずれかの記事でコメントフォームを入力して送信します。
すると、コメントはコメント欄に反映されますが、フォームには前に入力した内容が残っています。
この問題の原因を検出するデバッグをします。

サーバーを起動します。

terminal
$ python manage.py runserver

起動させたら、いずれかのブログ記事でコメントフォームを入力して送信します。
すると、

terminal
> /Users/Kazuki/todo/django_blog/blogs/views.py(16)detail()
-> blog = Blog.objects.get(id=blog_id)

が表示されます。
ここで、lを入力すると、

terminal
> /Users/Kazuki/todo/django_blog/blogs/views.py(16)detail()
-> blog = Blog.objects.get(id=blog_id)
(Pdb) l
 14     def detail(request, blog_id):
 15         import pdb; pdb.set_trace()
 16  ->     blog = Blog.objects.get(id=blog_id)
 17         comments = Comment.objects.filter(post=blog)
 18
 19         if request.method == "POST":
 20             form = forms.CommentForm(request.POST)
 21             if form.is_valid():

と、コードの一部が表示され、これから実行する行に矢印が付いています。
今回は、29行目でreturnする時点でフォームがどのような状態になっているのかを見たいので、29行目にブレークポイントを打ちます。

terminal
> /Users/Kazuki/todo/django_blog/blogs/views.py(16)detail()
-> blog = Blog.objects.get(id=blog_id)
(Pdb) b 29
Breakpoint 1 at /Users/kazuki/todo/django_blog/blogs/views.py:29

一気に29行目まで進めます。

terminal
(Pdb) c
> /Users/Kazuki/todo/django_blog/blogs/views.py(29)
-> return render(request, 'blogs/detail.html', {'blog': blog, 'form':form, 'comments':comments})

ここで、フォームの状態を確かめてみます。

terminal
(Pdb) p form
<CommentForm bound=True, valid=Unknown, fields=(text)>

フォームのboundTrueになっています。
つまり、フォームに送信可能なデータが入っているということです。
これをFalseの状態にするには、views.pyファイルで、

blogs/views.py
#            form = forms.CommentForm() #いったんコメントアウト

の一文をコメントアウトから戻し、もう一度フォームを送信すると、フォームに前に入力した内容が残りません。
実際、デバッグしてみると、

terminal
(Pdb) p form
<CommentForm bound=False, valid=Unknown, fields=(text)>

と表示され、boundFalseになっています。

テスト

次に、アプリのテストを書いていきます。

blogs/test.py
from django.urls import resolve
from django.test import TestCase
from blogs.views import index, detail, signup

from django.http import HttpRequest
from django.template.loader import render_to_string

#各URLで対応するviewが起動されることを検証
class UrlResolveTest(TestCase):
    def test_url_resolves_to_index_view(self):
        found = resolve('/')
        self.assertEqual(found.func, index)

    def test_url_resolves_to_detail_view(self):
        found = resolve('/detail/3/')
        self.assertEqual(found.func, detail)

    def test_url_resolves_to_signup_view(self):
        found = resolve('/signup/')

#正しいHTMLが返されることを検証
class HtmlTest(TestCase):
    def test_index_page_returns_correct_html(self):
        request = HttpRequest()
        response = index(request)
        expected_html = render_to_string('blogs/index.html', {'blogs': []})
        self.assertEqual(response.content.decode(), expected_html)

テストしてみます。

terminal
$ python manage.py test
Creating test database for alias 'default'...
...
----------------------------------------------------------------------
Ran 4 tests in 0.060s

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

テスト通過しました。