【初学者】【Python/Django】刚入门的Web工程师尝试完成Django教程之五

首先

大家好,初次见面。
我打算将使用Django创建投票应用程序的过程作为备忘录进行公开。
由于我是Qiita的初学者,可能会有一些难以理解的部分,请大家谅解。

系列 (xì liè)

    • 【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた~その0~

 

    • 【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた~その1~

 

    • 【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた~その2~

 

    • 【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた~その3~

 

    【初心者】【Python/Django】駆け出しWebエンジニアがDjangoチュートリアルをやってみた~その4~

开始工作

引入自動測試

我会编写使用Django自动测试功能的代码。

首次考试的准备

在Django中,进行测试需要哪些代码?首先,我们将以对话的形式执行测试。

测试内容:检查问题的发布日期(从今天起30天后)如果是未来的日期,则was_published_recently函数返回False。
测试结果:失败(was_published_recently的预期行为应为False,但实际行为为True)。


(poll-HcNSSqhc) C:\django\poll>python manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:37:30) [MSC v.1927 32 bit (Intel)] on win32     
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>>
>>> future_question = Question(pub_date=timezone.now()+datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True
>>>

我会将其编码成代码。
我正在使用self.assertIs来期望其行为为False。


from django.test import TestCase

import datetime
from django.utils import timezone
from .models import Question

# Create your tests here.


class QuestionModelTests(TestCase):
    def test_was_published_recently_whit_future_question(self):
        future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
        self.assertIs(future_question.was_published_recently(), False)

接下来,我们来进行测试。当然,这不是一个互动类型的测试。


(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_whit_future_question (polls.tests.QuestionModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\django\poll\polls\tests.py", line 13, in test_was_published_recently_whit_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)
Destroying test database for alias 'default'...

(poll-HcNSSqhc) C:\django\poll>

严格地返回了FAILD。(虽然was_published_recently期望为False,但实际的操作结果为True)

让我们进行调试。


    def was_published_recently(self):
        return timezone.now() - datetime.timedelta(days=1) <= self.pub_date <= timezone.now()

(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.002s

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

(poll-HcNSSqhc) C:\django\poll>

好的,(was_published_recently的预期操作是False,实际操作也是False)。

更加全面的的测试

让我们在同一个班级中添加更多的测试项目。我们正在增加边界值测试项目。


    def test_was_published_recently_with_old_question(self):
        old_question = Question(pub_date=timezone.now() - datetime.timedelta(days=1, seconds=1))
        self.assertIs(old_question.was_published_recently(), False)

    def test_was_published_recently_with_recently_question(self):
        recently_question = Question(pub_date=timezone.now(
        ) - datetime.timedelta(hours=23, minutes=59, seconds=59))
        self.assertIs(recently_question.was_published_recently(), True)

(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.004s

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

(poll-HcNSSqhc) C:\django\poll>

被显示为“好”。

测试视图

首先,要在Django中进行视图测试,需要使用Client类。
首先,通过对话形式执行测试。

测试内容:检查是否存在“http://127.0.0.1/polls”的视图
测试结果:HTTP200,并且能够获取到内容。


(poll-HcNSSqhc) C:\django\poll>python manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:37:30) [MSC v.1927 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 
>>> 
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()  
>>> from django.test import Client
>>> from django.urls import reverse
>>> client = Client()
>>> response = client.get(reverse('polls:index'))      
>>> 
>>> response.status_code
200
>>>
>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/5/">What&#x27;s this?</a></li>\n    \n    </ul>\n'
>>>
>>> response.context['latest_question_list'] 
<QuerySet [<Question: What's this?>]>
>>>

改善视图

由于显示了未来日期的投票问题,请进行改修。

Question.objects.filter()意味着筛选问题,pub_date__lte=timezone.now()表示pub_date小于或等于timezone.now()的条件表达式。


from django.utils import timezone

class IndexView(generic.ListView):
    ***
    def get_queryset(self):
        return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]

测试新视图

我会准备测试代码。


from django.urls import reverse

def create_question(question_text, days):
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)


class QuestionIndexViewTest(TestCase):
    # HTTP200、画面メッセージ:No polls are available.、質問リスト:空
    def test_no_question(self):
        response = self.client.get(reverse('polls:index'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    # 質問リスト:Past question.
    def test_past_question(self):
        create_question(question_text="Past question.", days=-30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(response.context['latest_question_list'], [
                                 '<Question: Past question.>'])

    # 質問リスト:空(未来の質問は表示されない)
    def test_feature_question(self):
        create_question(question_text="Feature question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    # 質問リスト:Past question.(未来の質問は表示されない)
    def test_feature_question_and_past_question(self):
        create_question(question_text="Feature question.", days=30)
        create_question(question_text="Past question.", days=-30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(response.context['latest_question_list'], [
                                 '<Question: Past question.>'])

    # 質問リスト:Past question1.、Past question2.
    # 質問リストは最新投稿順に取得されるため、作成順序と取得順序が弱になることに注意
    def test_tow_past_question(self):
        create_question(question_text="Past question1.", days=-30)
        create_question(question_text="Past question2.", days=-10)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(response.context['latest_question_list'], [
                                 '<Question: Past question2.>', '<Question: Past question1.>'])

(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
........
----------------------------------------------------------------------
Ran 8 tests in 0.063s

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

(poll-HcNSSqhc) C:\django\poll>

显示了OK。

详细视图测试

由於詳細視圖已經可以顯示未來日期的問題詳細信息,因此我們需要進行改修。


class DetailView(generic.DetailView):
  ***
    def get_queryset(self):
        return Question.objects.filter(pub_date__lte=timezone.now())

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        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):
        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)

(poll-HcNSSqhc) C:\django\poll>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..........
----------------------------------------------------------------------
Ran 10 tests in 0.088s

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

(poll-HcNSSqhc) C:\django\poll>

我今天就到这里了。非常感谢。

bannerAds