Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

finish rewriting tutorial 4

  • Loading branch information...
commit 64ae7bd5522c5e599a54cd0e5b654b8406225ec7 1 parent 5279916
@hjwp authored
View
35 mysite/fts/tests.py
@@ -188,22 +188,37 @@ def test_voting_on_a_new_poll(self):
body = self.browser.find_element_by_tag_name('body')
self.assertIn('No-one has voted on this poll yet', body.text)
- self.fail('TODO')
-
- # He clicks on the link to the first Poll, which is called
- # 'How awesome is test-driven development?'
-
- # He is taken to a poll 'results' page, which says
- # "no-one has voted on this poll yet"
-
# He also sees a form, which offers him several choices.
- # He decided to select "very awesome"
+ # There are three options with radio buttons
+ choice_inputs = self.browser.find_elements_by_css_selector(
+ "input[type='radio']"
+ )
+ self.assertEquals(len(choice_inputs), 3)
+
+ # The buttons have labels to explain them
+ choice_labels = self.browser.find_elements_by_tag_name('label')
+ choices_text = [c.text for c in choice_labels]
+ self.assertEquals(choices_text, [
+ 'Vote:', # this label is auto-generated for the whole form
+ 'Very awesome',
+ 'Quite awesome',
+ 'Moderately awesome',
+ ])
+ # He decided to select "very awesome", which is answer #1
+ chosen = self.browser.find_element_by_css_selector(
+ "input[value='1']"
+ )
+ chosen.click()
- # He clicks 'submit'
+ # Herbert clicks 'submit'
+ self.browser.find_element_by_css_selector(
+ "input[type='submit']"
+ ).click()
# The page refreshes, and he sees that his choice
# has updated the results. they now say
# "100 %: very awesome".
+ self.fail('TODO')
# The page also says "1 votes"
View
8 mysite/polls/forms.py
@@ -0,0 +1,8 @@
+from django import forms
+
+class PollVoteForm(forms.Form):
+ vote = forms.ChoiceField(widget=forms.RadioSelect())
+
+ def __init__(self, poll):
+ forms.Form.__init__(self)
+ self.fields['vote'].choices = [(c.id, c.choice) for c in poll.choice_set.all()]
View
14 mysite/polls/templates/poll.html
@@ -0,0 +1,14 @@
+<html>
+ <body>
+ <h1>Poll Results</h1>
+
+ <h2>{{poll.question}}</h2>
+
+ <p>No-one has voted on this poll yet</p>
+
+ <h3>Add your vote</h3>
+ {{form.as_p}}
+ <input type="submit" />
+
+ </body>
+</html>
View
81 mysite/polls/tests.py
@@ -78,6 +78,8 @@ def test_choice_defaults(self):
choice = Choice()
self.assertEquals(choice.votes, 0)
+
+
class TestHomePageView(TestCase):
def test_root_url_shows_links_to_all_polls(self):
@@ -105,3 +107,82 @@ def test_root_url_shows_links_to_all_polls(self):
self.assertIn(poll1_url, response.content)
poll2_url = reverse('polls.views.poll', args=[poll2.id,])
self.assertIn(poll2_url, response.content)
+
+
+
+class TestSinglePollView(TestCase):
+
+ def test_page_shows_poll_title_and_no_votes_message(self):
+ # set up two polls, to check the right one is displayed
+ poll1 = Poll(question='6 times 7', pub_date=timezone.now())
+ poll1.save()
+ poll2 = Poll(question='life, the universe and everything', pub_date=timezone.now())
+ poll2.save()
+
+ response = self.client.get('/poll/%d/' % (poll2.id, ))
+
+ # check we've used the poll template
+ self.assertTemplateUsed(response, 'poll.html')
+
+ # check we've passed the right poll into the context
+ self.assertEquals(response.context['poll'], poll2)
+
+ # check the poll's question appears on the page
+ self.assertIn(poll2.question, response.content)
+
+ # check our 'no votes yet' message appears
+ self.assertIn('No-one has voted on this poll yet', response.content)
+
+from polls.forms import PollVoteForm
+
+class TestPollsVoteForm(TestCase):
+
+ def test_form_renders_poll_choices_as_radio_inputs(self):
+ # set up a poll with a couple of choices
+ poll1 = Poll(question='6 times 7', pub_date=timezone.now())
+ poll1.save()
+ choice1 = Choice(poll=poll1, choice='42', votes=0)
+ choice1.save()
+ choice2 = Choice(poll=poll1, choice='The Ultimate Answer', votes=0)
+ choice2.save()
+
+ # set up another poll to make sure we only see the right choices
+ poll2 = Poll(question='time', pub_date=timezone.now())
+ poll2.save()
+ choice3 = Choice(poll=poll2, choice='PM', votes=0)
+ choice3.save()
+
+ # build a voting form for poll1
+ form = PollVoteForm(poll=poll1)
+
+ # check it has a single field called 'vote', which has right choices:
+ self.assertEquals(form.fields.keys(), ['vote'])
+
+ # choices are tuples in the format (choice_number, choice_text):
+ self.assertEquals(form.fields['vote'].choices, [
+ (choice1.id, choice1.choice),
+ (choice2.id, choice2.choice),
+ ])
+
+ # check it uses radio inputs to render
+ self.assertIn('input type="radio"', form.as_p())
+
+
+ def test_page_shows_choices_using_form(self):
+ # set up a poll with choices
+ poll1 = Poll(question='time', pub_date=timezone.now())
+ poll1.save()
+ choice1 = Choice(poll=poll1, choice="PM", votes=0)
+ choice1.save()
+ choice2 = Choice(poll=poll1, choice="Gardener's", votes=0)
+ choice2.save()
+
+ response = self.client.get('/poll/%d/' % (poll1.id, ))
+
+ # check we've passed in a form of the right type
+ self.assertTrue(isinstance(response.context['form'], PollVoteForm))
+
+ # and check the check the form is being used in the template,
+ # by checking for the choice text
+ self.assertIn(choice1.choice, response.content.replace('&#39;', "'"))
+ self.assertIn(choice2.choice, response.content.replace('&#39;', "'"))
View
10 mysite/polls/views.py
@@ -1,10 +1,14 @@
-from polls.models import Poll
from django.shortcuts import render
+from polls.forms import PollVoteForm
+from polls.models import Poll
+
def home(request):
context = {'polls': Poll.objects.all()}
return render(request, 'home.html', context)
-def poll():
- pass
+def poll(request, poll_id):
+ poll = Poll.objects.get(pk=poll_id)
+ form = PollVoteForm(poll=poll)
+ return render(request, 'poll.html', {'poll': poll, 'form': form})
View
45 tutorial04.rst
@@ -15,15 +15,15 @@ Here's the outline of what we're going to do in this tutorial:
Extending the FT to vote using radio buttons
--------------------------------------------
-Let's start by extending our FT, to show Herbert voting on a poll. In ``fts/test_polls.py``:
+Let's start by extending our FT, to show Herbert voting on a poll. In ``fts/tests.py``:
.. sourcecode:: python
- :filename: mysite/fts/test_polls.py
+ :filename: mysite/fts/tests.py
[...]
# Now, Herbert the regular user goes to the homepage of the site. He
# sees a list of polls.
- self.browser.get(ROOT)
+ self.browser.get(self.live_server_url)
heading = self.browser.find_element_by_tag_name('h1')
self.assertEquals(heading.text, 'Polls')
@@ -77,18 +77,9 @@ Let's start by extending our FT, to show Herbert voting on a poll. In ``fts/test
# Satisfied, he goes back to sleep
-If you run them, you'll find that they are still telling us about a "TypeError" on
-the individual poll page though::
+If you run them, you'll find that they are still telling us the individual poll page isn't working::
- ======================================================================
- FAIL: test_voting_on_a_new_poll (test_polls.TestPolls)
- ----------------------------------------------------------------------
- Traceback (most recent call last):
- File "/home/harry/workspace/tddjango_site/source/mysite/fts/test_polls.py", line 67, in test_voting_on_a_new_poll
- self.assertEquals(heading.text, 'Poll Results')
- AssertionError: u'TypeError at /poll/1/' != 'Poll Results'
- ----------------------------------------------------------------------
- Ran 2 tests in 25.927s
+ NoSuchElementException: Message: u'Unable to locate element: {"method":"tag name","selector":"h1"}'
That because, currently, our ``poll`` view is just a placeholder function. We need
@@ -109,8 +100,7 @@ in ``polls/tests.py``:
poll2 = Poll(question='life, the universe and everything', pub_date=timezone.now())
poll2.save()
- client = Client()
- response = client.get('/poll/%d/' % (poll2.id, ))
+ response = self.client.get('/poll/%d/' % (poll2.id, ))
# check we've used the poll template
self.assertTemplateUsed(response, 'poll.html')
@@ -214,7 +204,7 @@ In the meantime, what do the tests say::
We need to get our template to include the poll's question. Let's make it into a page heading:
.. sourcecode:: html+django
- :filename: mysite/polls/templates/home.html
+ :filename: mysite/polls/templates/poll.html
<html>
<body>
@@ -255,7 +245,7 @@ Mmmh, `OK`. And doughnuts. Let's see what the FTs think?::
Ah, we forgot to include a general heading for the page - the FT is checking the ``h1`` and ``h2`` headings:
.. sourcecode:: python
- :filename: mysite/fts/test_polls.py
+ :filename: mysite/fts/tests.py
main_heading = self.browser.find_element_by_tag_name('h1')
self.assertEquals(main_heading.text, 'Poll Results')
@@ -285,10 +275,10 @@ Using a Django form for poll choices
Now what does the FT say?::
======================================================================
- FAIL: test_voting_on_a_new_poll (test_polls.TestPolls)
+ FAIL: test_voting_on_a_new_poll (tests.TestPolls)
----------------------------------------------------------------------
Traceback (most recent call last):
- File "/home/harry/workspace/mysite/fts/test_polls.py", line 100, in test_voting_on_a_new_poll
+ File "/home/harry/workspace/mysite/fts/tests.py", line 100, in test_voting_on_a_new_poll
self.assertEquals(len(choice_inputs), 3)
AssertionError: 0 != 3
@@ -464,8 +454,7 @@ Ah yes, we still haven't actually *used* the form yet! Let's go back to our ``T
choice2 = Choice(poll=poll1, choice="Gardener's", votes=0)
choice2.save()
- client = Client()
- response = client.get('/poll/%d/' % (poll1.id, ))
+ response = self.client.get('/poll/%d/' % (poll1.id, ))
# check we've passed in a form of the right type
self.assertTrue(isinstance(response.context['form'], PollVoteForm))
@@ -557,10 +546,10 @@ And now we have passination::
So let's ask the FTs again!::
======================================================================
- FAIL: test_voting_on_a_new_poll (test_polls.TestPolls)
+ FAIL: test_voting_on_a_new_poll (tests.TestPolls)
----------------------------------------------------------------------
Traceback (most recent call last):
- File "/home/harry/workspace/tddjango_site/source/mysite/fts/test_polls.py", line 84, in test_voting_on_a_new_poll
+ File "/home/harry/workspace/tddjango_site/source/mysite/fts/tests.py", line 84, in test_voting_on_a_new_poll
'Moderately awesome',
AssertionError: Lists differ: [u'Vote:', u'Very awesome', u'... != ['Very awesome', 'Quite awesom...
@@ -582,7 +571,7 @@ So let's ask the FTs again!::
Hm, not quite according to the original plan - our form has auto-generated an extra label which says "Vote:" above the radio buttons - well, since it doesn't do any harm, for now maybe it's easiest to just change the FT:
.. sourcecode:: python
- :filename: mysite/fts/test_polls.py
+ :filename: mysite/fts/tests.py
# He also sees a form, which offers him several choices.
# There are three options with radio buttons
@@ -611,7 +600,7 @@ There's no submit button on our form! When Django generates a form, it only give
Well, a button is easy enough to add, although it may not do much... In the template:
.. sourcecode:: html+django
- :filename: mysite/polls/templates/home.html
+ :filename: mysite/polls/templates/poll.html
<html>
<body>
@@ -633,10 +622,10 @@ Well, a button is easy enough to add, although it may not do much... In the temp
And now... our tests get to the end!::
======================================================================
- FAIL: test_voting_on_a_new_poll (test_polls.TestPolls)
+ FAIL: test_voting_on_a_new_poll (tests.TestPolls)
----------------------------------------------------------------------
Traceback (most recent call last):
- File "/home/harry/workspace/tddjango_site/source/mysite/fts/test_polls.py", line 125, in test_voting_on_a_new_poll
+ File "/home/harry/workspace/tddjango_site/source/mysite/fts/tests.py", line 125, in test_voting_on_a_new_poll
self.fail('TODO')
AssertionError: TODO
----------------------------------------------------------------------
Please sign in to comment.
Something went wrong with that request. Please try again.