Django入门笔记【五】

入门笔记翻译整理自:https://docs.djangoproject.com/en/1.8/

*该笔记将使用一个关于投票网络应用(poll application)的例子来阐述Django的用法。

*自动测试(automated testing)

1. 首个测试

Question.was_published_recently()方法中有一个小问题,它会将未来的时间也显示为昨日发布。

使用shell来测试:

1 >>> import datetime
2 >>> from django.utils import timezone
3 >>> from polls.models import Question
4 >>> # create a Question instance with pub_date 30 days in the future
5 >>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
6 >>> # was it published recently?
7 >>> future_question.was_published_recently()
8 True

2. 创建测试

测试系统会自动寻找任何以test开头的文件。在polls里创建tests.py:

 1 # polls/tests.py
 2 
 3 import datetime
 4 
 5 from django.utils import timezone
 6 from django.test import TestCase
 7 
 8 from .models import Question
 9 
10 class QuestionMethodTests(TestCase):
11     
12     def test_was_published_recently_with_future_question(self):
13         """
14         was_published_recently should return False for questions whose     
15         pub_date is in the future.
16         """
17         time = timezone.now() + datetime.timedelta(days=30)
18         future_question = Question(pubdate=time)
19         self.assertEqual(future_question.was_published_recently(), False)

 

3. 运行测试 

运行代码 $ python manage.py test polls 

4. 订正错误

1 # polls/models.py
2 
3 def was_published_recently(self):
4     now = timezone.now()
5     return now - datetime.timedelta(days=1) <= self.pub_date <= now

 

再次运行测试

5. 更复杂的测试

为了防止订正带来更多的错误,添加代码:

 1 # polls/tests.py
 2 
 3 def test_was_published_recently_with_old_question(self):
 4     """
 5     was_published_recently() should return False for questions whose 
 6     pub_date is older than 1 day.
 7     """
 8     time = timezone.now() - datetime.timedelta(days=30)
 9     old_question = Question(pub_date=time)
10     self.assertEqual(old_question.was_published_recently(), False)
11 
12 def test_was_published_recently_with_recent_question(self):
13     """
14     was_published_recently() should return True for questions whose
15     pub_date is within the last day.
16     """
17     time = timezone.now() - datetime.timedelta(hours=1)
18     recent_question = Question(pub_date=time)
19     self.assertEqual(recent_question.was_published_recently(), True)

 

6. 测试视图(Test a view)

Django提供了测试Client来模拟用户和视图的交互。我们可以在test.py或者shell中使用它。

先来看shell,初始化环境:

1 >>> from django.test.utils import setup_test_environment
2 >>> setup_test_environment()

再来导入Client:

1 >>> from django.test import Client
2 >>> # create an instance of the client for our use
3 >>> client = Client()

 接下来:

 1 >>> # get a response from '/'
 2 >>> response = client.get('/')
 3 >>> # we should expect a 404 from that address
 4 >>> response.status_code
 5 404
 6 >>> # on the other hand we should expect to find something at '/polls/'
 7 >>> # we'll use 'reverse()' rather than a hardcoded URL
 8 >>> from django.core.urlresolvers import reverse
 9 >>> response = client.get(reverse('polls: index'))
10 >>> response.status_code
11 200
12 >>> response.content
13 '\n\n\n    <p>No polls are available.</p>\n\n'
14 >>> #note - you might get unexpected results of your ``TIME_ZONE``
15 >>> # in ``settings.py`` is not correct. If you need to change it,
16 >>> # you will also need to restart your shell session
17 >>> from polls.models import Question
18 >>> from django.utils import timezone
19 >>> # create a Question and save it
20 >>> q = Question(question_text="Who is your favorite Beatle?", pub_date=timezone.now())
21 >>> q.save()
22 >>> # check the response once again
23 >>> response = client.get('/polls/')
24 >>> response.content
25 '\n\n\n    <ul>\n    \n        <li><a href="/polls/1/">Who is your favorite Beatle?</a>
26 </li>\n    \n    </ul>\n\n'
27 >>> # If the following doesn't work, you probably omitted the call to
28 >>> # setup_test_environment() described above
29 >>> response.context['latest_question_list']
30 [<Question: Who is your favorite Beatle?>]

将视图

1 # polls/views.py
2 
3 class IndexView(generic.ListView):
4     template_name = 'polls/index.html'
5     context_object_name = 'latest_question_list'
6     
7     def get_queryset(self):
8         """Return the last five published questions."""
9         return Question.objects.order_by('-pub_date')[:5]

改进为:

 1 # polls/views.py
 2 from django.utils import timezone
 3 # 同时修改get_queryset方法
 4 def get_queryset(self):
 5     """
 6     Return the last five published questions (not including those set to
 7     be published in the future).
 8     """
 9     return Question.objects.filter(
10         pub_date_lte=timezone.now()
11     ).order_by('-pub_date')[:5]

接下来,基于之前在Shell里做的,我们来创建一个test文件:

 1 # polls/tests.py
 2 
 3 def create_question(question_text, days):
 4     """
 5     Creates a question with the given `question_text` published the given
 6     number of `days` offset to now (negative for questions published
 7     in the past, positive for questions that have yet to be published).
 8     """
 9     time = timezone.now() + datetime.timedelta(days=days)
10     return Question.objects.create(question_text=question_text,
11                                    pub_date=time)
12 
13 
14 class QuestionViewTests(TestCase):
15     def test_index_view_with_no_questions(self):
16         """
17         If no questions exist, an appropriate message should be displayed.
18         """
19         response = self.client.get(reverse('polls:index'))
20         self.assertEqual(response.status_code, 200)
21         self.assertContains(response, "No polls are available.")
22         self.assertQuerysetEqual(response.context['latest_question_list'], [])
23 
24     def test_index_view_with_a_past_question(self):
25         """
26         Questions with a pub_date in the past should be displayed on the
27         index page.
28         """
29         create_question(question_text="Past question.", days=-30)
30         response = self.client.get(reverse('polls:index'))
31         self.assertQuerysetEqual(
32             response.context['latest_question_list'],
33             ['<Question: Past question.>']
34         )
35 
36     def test_index_view_with_a_future_question(self):
37         """
38         Questions with a pub_date in the future should not be displayed on
39         the index page.
40         """
41         create_question(question_text="Future question.", days=30)
42         response = self.client.get(reverse('polls:index'))
43         self.assertContains(response, "No polls are available.",
44                             status_code=200)
45         self.assertQuerysetEqual(response.context['latest_question_list'], [])
46 
47     def test_index_view_with_future_question_and_past_question(self):
48         """
49         Even if both past and future questions exist, only past questions
50         should be displayed.
51         """
52         create_question(question_text="Past question.", days=-30)
53         create_question(question_text="Future question.", days=30)
54         response = self.client.get(reverse('polls:index'))
55         self.assertQuerysetEqual(
56             response.context['latest_question_list'],
57             ['<Question: Past question.>']
58         )
59 
60     def test_index_view_with_two_past_questions(self):
61         """
62         The questions index page may display multiple questions.
63         """
64         create_question(question_text="Past question 1.", days=-30)
65         create_question(question_text="Past question 2.", days=-5)
66         response = self.client.get(reverse('polls:index'))
67         self.assertQuerysetEqual(
68             response.context['latest_question_list'],
69             ['<Question: Past question 2.>', '<Question: Past question 1.>']
70         )

 

到目前为止,还不错。但是,如果用户仍然可以通过猜测,来进入未来的问题中,因此我们对DetailView也做相应改变:

1 # polls/views.py
2 
3 class DetailView(generic.DetailView):
4     ...
5     def get_queryset(self):
6         """
7         Excludes any questions that aren't published yet.
8         """
9         return Question.objects.filter(pub_date__lte=timezone.now())

 

接下来,对此进行测试:

# polls/tests.py

class QuestionIndexDetailTests(TestCase):
    def test_detail_view_with_a_future_question(self):
        """
        The detail view of a question with a pub_date in the future should
        return a 404 not found.
        """
        future_question = create_question(question_text='Future question.',
                                          days=5)
        response = self.client.get(reverse('polls:detail',
                                   args=(future_question.id,)))
        self.assertEqual(response.status_code, 404)

    def test_detail_view_with_a_past_question(self):
        """
        The detail view of a question with a pub_date in the past should
        display the question's text.
        """
        past_question = create_question(question_text='Past Question.',
                                        days=-5)
        response = self.client.get(reverse('polls:detail',
                                   args=(past_question.id,)))
        self.assertContains(response, past_question.question_text,
                            status_code=200)

 

 

-- The End --

 

posted @ 2015-06-25 12:16  py_drama  阅读(278)  评论(0编辑  收藏  举报