Skip to content

Commit

Permalink
django
Browse files Browse the repository at this point in the history
  • Loading branch information
imuradevelopment committed Jan 17, 2021
1 parent 42e538e commit 5609ca4
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 24 deletions.
114 changes: 112 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,8 @@ class Question(models.Model):
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now


class Choice(models.Model):
Expand Down Expand Up @@ -807,20 +808,35 @@ class ResultsView(generic.DetailView):
template_name = 'polls/results.html'
```
15. 自動テストの導入
- モデルやビューごとに TestClass を分割する
- テストしたい条件の集まりのそれぞれに対して、異なるテストメソッドを作る
- テストメソッドの名前は、その機能を説明するようなものにする
- Django には、Selenium のようなツールとの連携を容易にしてくれる "LiveServerTestCase" が用意されています。
- アプリケーションのテストされていない部分を発見するには、コードカバレッジ "[Integration with coverage.py](https://docs.djangoproject.com/ja/2.2/topics/testing/advanced/#topics-testing-code-coverage)"
```python
# polls/tests.py
import datetime

from django.test import TestCase
from django.utils import timezone
from django.urls import reverse

from .models import Question

"""テスト用のメソッドとして、test で始まるメソッドを作成。"""
"""
テスト用のメソッドとして、test で始まるメソッドを作成する。
データベースは各テストメソッドごとにリセット
"""

"""
modelのテスト
models.py
"""
class QuestionModelTests(TestCase):

def test_was_published_recently_with_future_question(self):
"""
テスト用のメソッドとして、test で始まるメソッドを作成。
was_published_recently()は、pub_dateが将来の質問に対してFalseを返します。
"""
time = timezone.now() + datetime.timedelta(days=30)
Expand All @@ -843,6 +859,98 @@ class QuestionModelTests(TestCase):
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)


"""
Viewのテスト
views.py
"""
"""IndexView"""
def create_question(question_text, days):
"""
指定された「question_text」を使用して質問を作成し、指定された「日数」を現在までオフセットにして公開します。
(過去に公開された質問の場合は公表、まだ公開されていない質問の場合は非公表)。
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)


class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
"""
質問が存在しない場合は、適切なメッセージが表示されます。
"""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "投票は利用できません。")
self.assertQuerysetEqual(response.context['latest_question_list'], [])

def test_past_question(self):
"""
過去にpub_dateを使用した質問は、インデックスページに表示されます。
"""
create_question(question_text="過去の質問", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問>']
)

def test_future_question(self):
"""
今日以降のpub_dateを含む質問は、インデックスページに表示されません。
"""
create_question(question_text="未来の質問", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "投票は利用できません。")
self.assertQuerysetEqual(response.context['latest_question_list'], [])

def test_future_question_and_past_question(self):
"""
過去と未来の両方の質問が存在する場合でも、過去の質問のみが表示されます。
"""
create_question(question_text="過去の質問", days=-30)
create_question(question_text="未来の質問", days=30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問>']
)

def test_two_past_questions(self):
"""
質問のインデックスページには、複数の質問が表示される場合があります。
"""
create_question(question_text="過去の質問 1", days=-30)
create_question(question_text="過去の質問 2", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問 2>', '<Question: 過去の質問 1>']
)


"""DetailView"""
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
"""
未来のpub_dateを含む質問の詳細ビューは、404notfoundを返します。
"""
future_question = create_question(
question_text='Future question.', days=5)
url = reverse('polls:detail', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)

def test_past_question(self):
"""
過去のpub_dateを使用した質問の詳細ビューは、質問のテキストが表示されます。
"""
past_question = create_question(
question_text='Past Question.', days=-5)
url = reverse('polls:detail', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)

```

16. テストの実行
Expand Down Expand Up @@ -878,6 +986,8 @@ Ran 1 test in 0.002s
OK
Destroying test database for alias 'default'...
```
17. アプリ の構造をカスタマイズする

### プログラム実行順

1. mysite/manage.py
Expand Down
Binary file modified django/mysite/mysite/__pycache__/settings.cpython-38.pyc
Binary file not shown.
20 changes: 18 additions & 2 deletions django/mysite/mysite/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""

import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
Expand Down Expand Up @@ -52,7 +52,7 @@
]

ROOT_URLCONF = 'mysite.urls'

"""
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
Expand All @@ -68,6 +68,22 @@
},
},
]
"""
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'mysite.wsgi.application'

Expand Down
Binary file modified django/mysite/polls/__pycache__/admin.cpython-38.pyc
Binary file not shown.
Binary file modified django/mysite/polls/__pycache__/models.cpython-38.pyc
Binary file not shown.
Binary file modified django/mysite/polls/__pycache__/tests.cpython-38.pyc
Binary file not shown.
Binary file modified django/mysite/polls/__pycache__/views.cpython-38.pyc
Binary file not shown.
29 changes: 27 additions & 2 deletions django/mysite/polls/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,30 @@

from .models import Question, Choice

admin.site.register(Question)
admin.site.register(Choice)

class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('日付情報', {'fields': ['pub_date']}),
]


#class ChoiceInline(admin.StackedInline):
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3


class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('日付情報', {'fields': [
'pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
#list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']


admin.site.register(Question, QuestionAdmin)
#admin.site.register(Question, QuestionAdmin)
3 changes: 3 additions & 0 deletions django/mysite/polls/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ def __str__(self):
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = '最近公開されましたか?'

class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
Expand Down
6 changes: 6 additions & 0 deletions django/mysite/polls/static/polls/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
li a {
color: green;
}
body {
background: white url("images/background.gif") no-repeat;
}
18 changes: 4 additions & 14 deletions django/mysite/polls/templates/polls/index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
<!--<div>
<form action="//www-creators.com/rsc/receiver.php" method="post">
<label class="label" for="message">質問を投稿する</label>
<textarea rows="4" id="message" placeholder="20文字以内で入力してください。" name="comment"></textarea>
<input type="submit">
</form>
<style>
label, input[type=text]{
display:block;
}
</style>
</div>
-->
{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">

{% if latest_question_list %}
<ul>
Expand All @@ -20,5 +10,5 @@
{% endfor %}
</ul>
{% else %}
<p>投票は利用できません</p>
<p>投票は利用できません</p>
{% endif %}
103 changes: 102 additions & 1 deletion django/mysite/polls/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@

from django.test import TestCase
from django.utils import timezone
from django.urls import reverse

from .models import Question

"""テスト用のメソッドとして、test で始まるメソッドを作成。"""
"""
テスト用のメソッドとして、test で始まるメソッドを作成する。
データベースは各テストメソッドごとにリセット
"""

"""
modelのテスト
models.py
"""
class QuestionModelTests(TestCase):

def test_was_published_recently_with_future_question(self):
Expand All @@ -32,3 +41,95 @@ def test_was_published_recently_with_recent_question(self):
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)


"""
Viewのテスト
views.py
"""
"""IndexView"""
def create_question(question_text, days):
"""
指定された「question_text」を使用して質問を作成し、指定された「日数」を現在までオフセットにして公開します。
(過去に公開された質問の場合は公表、まだ公開されていない質問の場合は非公表)。
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)


class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
"""
質問が存在しない場合は、適切なメッセージが表示されます。
"""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "投票は利用できません。")
self.assertQuerysetEqual(response.context['latest_question_list'], [])

def test_past_question(self):
"""
過去にpub_dateを使用した質問は、インデックスページに表示されます。
"""
create_question(question_text="過去の質問", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問>']
)

def test_future_question(self):
"""
今日以降のpub_dateを含む質問は、インデックスページに表示されません。
"""
create_question(question_text="未来の質問", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "投票は利用できません。")
self.assertQuerysetEqual(response.context['latest_question_list'], [])

def test_future_question_and_past_question(self):
"""
過去と未来の両方の質問が存在する場合でも、過去の質問のみが表示されます。
"""
create_question(question_text="過去の質問", days=-30)
create_question(question_text="未来の質問", days=30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問>']
)

def test_two_past_questions(self):
"""
質問のインデックスページには、複数の質問が表示される場合があります。
"""
create_question(question_text="過去の質問 1", days=-30)
create_question(question_text="過去の質問 2", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: 過去の質問 2>', '<Question: 過去の質問 1>']
)


"""DetailView"""
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
"""
未来のpub_dateを含む質問の詳細ビューは、404notfoundを返します。
"""
future_question = create_question(
question_text='Future question.', days=5)
url = reverse('polls:detail', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)

def test_past_question(self):
"""
過去のpub_dateを使用した質問の詳細ビューは、質問のテキストが表示されます。
"""
past_question = create_question(
question_text='Past Question.', days=-5)
url = reverse('polls:detail', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)
Loading

0 comments on commit 5609ca4

Please sign in to comment.