Django学习5:test

版权声明:本文real_Rickys原创文章,未经real_Rickys允许不得转载。 https://blog.csdn.net/real_Rickys/article/details/82770955

Django学习5

 在平时测试代码的效用的时候通常会造成一系列的麻烦,消耗大量的时间,所以jiango提供了一个automated test。这些test可以发现错误的位置,它可以让代码更加通透,更易阅读。

step1:第一个test

 在例子中的这个项目是存在bug的如Question这个model的"was_published_recently"这个function中如果创建时间大于当前时间时,也会返回True,不过很明显,这个情况下的pub_date是非法数据。
 我们可以打开shell然后插入一个数据来测试一下。

In [1]: import datetime
In [2]: from django.utils import timezone
In [3]: from polls.models import Question
In [4]: future_question = Question(pub_date=timezone.now()+datetime.timedelta(days
   ...: =30))
In [5]: future_question.was_published_recently()
Out[5]: True

 可以看到这里发现了错误,但是这样来查找错误非常不方便,Django就为我们提供了automated test来完成这个步骤,testing system会自动找到那些以test开头的文件来测试。我们在文件结构下会发现一个polls/tests.py的文件,这就是Django默认生成的测试文件,在其中我们增加如下代码:

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


class QuestionModelTests(TestCase):

    def test_was_published_recently_with_future_question(self):

        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

 然后我们在终端中输入:

py manage.py test shell

 会出现“True is not False”的错误,这里“assertIs”就是回去运行"was_published_recently"这个函数放回"Ture"但是我们期望的是“False”。
 现在我们去修正一下这个方法然后再去运行一遍test,修正代码如下:

return timezone.now() >= self.pub_date >= timezone.now()-datetime.timedelta(days=1)

 发现test返回结果是“OK”

step2:更复杂的test

 在完成了上述的test,我们可以预见到,当一个bug修复后引起另一个
bug会发生什么,当一个melthod有数个地方需要test会怎样,那么同样用上面那个function来做例子:

class QuestionModelTests(TestCase):

    def test_was_published_recently_with_future_question(self):

        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

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

    def test_was_rececntly_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)

 这样就完整的测试了recent, old, future。

step3:view的test

 在对model的fuction有一个test后,我们发现我们的view也有问题,即是它会将所有的quesiton都进行显示,而不能进行筛选,有些question在设置的时候,时间会设置在未来以便表示是未来那个时间点再上线的question,现在是不可见的状态,但是我们的view会显示这样的question。
 在view的层面上,Django提供了一种test client来模拟用户的交互。下面我们可以使用shell来使用一下这个client,首先需要简历环境:

In [1]: from django.test.utils import setup_test_environment

In [2]: setup_test_environment()

 这里“setup_test_environment”就是会加载一个template的渲染器,它使得我们可以测试response的一些属性如"response.context"。注意的是它不会创建测试数据库,而是根据你的数据库来测试。如果Time_Zone没有设置正确还会导致一些奇怪的输出。
 接下来输入如下的代码:(教程中的代码)

>>> # get a response from '/'
>>> response = client.get('/')
Not Found: /
>>> # we should expect a 404 from that address; if you instead see an
>>> # "Invalid HTTP_HOST header" error and a 400 response, you probably
>>> # omitted the setup_test_environment() call described earlier.
>>> response.status_code
404
>>> # on the other hand we should expect to find something at '/polls/'
>>> # we'll use 'reverse()' rather than a hardcoded URL
>>> from django.urls import reverse
>>> response = client.get(reverse('polls:index'))
>>> response.status_code
200
>>> response.content
b'\n    <ul>\n    \n        <li><a href="/polls/1/">What&#39;s up?</a></li>\n    \n    </ul>\n\n'
>>> response.context['latest_question_list']
<QuerySet [<Question: What's up?>]>

step4:改进view

 在polls/views.py中将get_queryset改为如下:

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

 这里的这个".filter(pub_date__lte=timezone.now())代表pub_date小于等于timezone.now()的数据。

step5:测试新view

 这时候就修复了上述的bug,接下来就用test.py来测试一下。在test增加如下的class:

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 QuestionIndexViewTests(TestCase):

    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'], [])

    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_future_question(self):
        create_question(question_text="Future question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertContains(response, "No polls are available.")
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    def test_future_question_and_past_question(self):
        create_question(question_text="Past question.", days=-30)
        create_question(question_text="Future question.", days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question.>']
        )

    def test_two_past_questions(self):
        create_question(question_text="Past question 1.", days=-30)
        create_question(question_text="Past question 2.", days=-5)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question 2.>', '<Question: Past question 1.>']
        )

 在这其中需要解释的是“assertContains()”:代表response中包含的text;“assertQuerysetEqual()”:代表response中含有的list。

step6:测试detail的view

 除了index的view需要改变,detailview也需要改变,因为用户可能会通过猜测url来进入detail页面。所以将detail的view修改为:


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

    def get_queryset(self):
        return Question.objects.filter(
            pub_date__lte=timezone.now()
        )

 在test.py中加入:

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        """
        The detail view of a question with a pub_date in the future
        returns a 404 not found.
        """
        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):
        """
        The detail view of a question with a pub_date in the past
        displays the question's text.
        """
        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)

猜你喜欢

转载自blog.csdn.net/real_Rickys/article/details/82770955