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

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

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

## Pdbを用いたデバッグ

Pdbを用いてデバッグしてみます。
Pdbの使い方は、[こちらの記事](https://qiita.com/TakesxiSximada/items/45b6d71a44f2706798ed)を参考にしました。
views.pyを開き、コードにPdbのインポート文を追加します。

```python: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() #いったんコメントアウト
```

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

サーバーを起動します。

```bash:terminal
$ python manage.py runserver
```

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

```bash:terminal
> /Users/Kazuki/todo/django_blog/blogs/views.py(16)detail()
-> blog = Blog.objects.get(id=blog_id)
```
が表示されます。
ここで、```l```を入力すると、

```bash: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行目にブレークポイントを打ちます。

```bash: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行目まで進めます。

```bash:terminal
(Pdb) c
> /Users/Kazuki/todo/django_blog/blogs/views.py(29)
-> return render(request, 'blogs/detail.html', {'blog': blog, 'form':form, 'comments':comments})
```
ここで、フォームの状態を確かめてみます。

```bash:terminal
(Pdb) p form
<CommentForm bound=True, valid=Unknown, fields=(text)>
```
フォームの```bound```が```True```になっています。
つまり、フォームに送信可能なデータが入っているということです。
これを```False```の状態にするには、views.pyファイルで、

```python:blogs/views.py
#            form = forms.CommentForm() #いったんコメントアウト
```
の一文をコメントアウトから戻し、もう一度フォームを送信すると、フォームに前に入力した内容が残りません。
実際、デバッグしてみると、

```bash:terminal
(Pdb) p form
<CommentForm bound=False, valid=Unknown, fields=(text)>
```
と表示され、```bound```が```False```になっています。

##テスト

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

```python: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)
```

テストしてみます。

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

OK
Destroying test database for alias 'default'...
```
テスト通過しました。