Skip to content

Commit

Permalink
finish rewriting tutorial 4
Browse files Browse the repository at this point in the history
  • Loading branch information
hjwp committed Apr 9, 2012
1 parent 5279916 commit 64ae7bd
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 41 deletions.
35 changes: 25 additions & 10 deletions mysite/fts/tests.py
Expand Up @@ -188,22 +188,37 @@ def test_voting_on_a_new_poll(self):
body = self.browser.find_element_by_tag_name('body') body = self.browser.find_element_by_tag_name('body')
self.assertIn('No-one has voted on this poll yet', body.text) 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 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 # The page refreshes, and he sees that his choice
# has updated the results. they now say # has updated the results. they now say
# "100 %: very awesome". # "100 %: very awesome".
self.fail('TODO')


# The page also says "1 votes" # The page also says "1 votes"


Expand Down
8 changes: 8 additions & 0 deletions 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()]
14 changes: 14 additions & 0 deletions 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>
81 changes: 81 additions & 0 deletions mysite/polls/tests.py
Expand Up @@ -78,6 +78,8 @@ def test_choice_defaults(self):
choice = Choice() choice = Choice()
self.assertEquals(choice.votes, 0) self.assertEquals(choice.votes, 0)




class TestHomePageView(TestCase): class TestHomePageView(TestCase):


def test_root_url_shows_links_to_all_polls(self): def test_root_url_shows_links_to_all_polls(self):
Expand Down Expand Up @@ -105,3 +107,82 @@ def test_root_url_shows_links_to_all_polls(self):
self.assertIn(poll1_url, response.content) self.assertIn(poll1_url, response.content)
poll2_url = reverse('polls.views.poll', args=[poll2.id,]) poll2_url = reverse('polls.views.poll', args=[poll2.id,])
self.assertIn(poll2_url, response.content) 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;', "'"))
10 changes: 7 additions & 3 deletions mysite/polls/views.py
@@ -1,10 +1,14 @@
from polls.models import Poll
from django.shortcuts import render from django.shortcuts import render


from polls.forms import PollVoteForm
from polls.models import Poll

def home(request): def home(request):
context = {'polls': Poll.objects.all()} context = {'polls': Poll.objects.all()}
return render(request, 'home.html', context) return render(request, 'home.html', context)




def poll(): def poll(request, poll_id):
pass poll = Poll.objects.get(pk=poll_id)
form = PollVoteForm(poll=poll)
return render(request, 'poll.html', {'poll': poll, 'form': form})
45 changes: 17 additions & 28 deletions tutorial04.rst
Expand Up @@ -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 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 .. 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 # Now, Herbert the regular user goes to the homepage of the site. He
# sees a list of polls. # 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') heading = self.browser.find_element_by_tag_name('h1')
self.assertEquals(heading.text, 'Polls') self.assertEquals(heading.text, 'Polls')


Expand Down Expand Up @@ -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 # Satisfied, he goes back to sleep




If you run them, you'll find that they are still telling us about a "TypeError" on If you run them, you'll find that they are still telling us the individual poll page isn't working::
the individual poll page though::


====================================================================== NoSuchElementException: Message: u'Unable to locate element: {"method":"tag name","selector":"h1"}'
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




That because, currently, our ``poll`` view is just a placeholder function. We need That because, currently, our ``poll`` view is just a placeholder function. We need
Expand All @@ -109,8 +100,7 @@ in ``polls/tests.py``:
poll2 = Poll(question='life, the universe and everything', pub_date=timezone.now()) poll2 = Poll(question='life, the universe and everything', pub_date=timezone.now())
poll2.save() poll2.save()


client = Client() response = self.client.get('/poll/%d/' % (poll2.id, ))
response = client.get('/poll/%d/' % (poll2.id, ))


# check we've used the poll template # check we've used the poll template
self.assertTemplateUsed(response, 'poll.html') self.assertTemplateUsed(response, 'poll.html')
Expand Down Expand Up @@ -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: We need to get our template to include the poll's question. Let's make it into a page heading:


.. sourcecode:: html+django .. sourcecode:: html+django
:filename: mysite/polls/templates/home.html :filename: mysite/polls/templates/poll.html


<html> <html>
<body> <body>
Expand Down Expand Up @@ -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: Ah, we forgot to include a general heading for the page - the FT is checking the ``h1`` and ``h2`` headings:


.. sourcecode:: python .. sourcecode:: python
:filename: mysite/fts/test_polls.py :filename: mysite/fts/tests.py


main_heading = self.browser.find_element_by_tag_name('h1') main_heading = self.browser.find_element_by_tag_name('h1')
self.assertEquals(main_heading.text, 'Poll Results') self.assertEquals(main_heading.text, 'Poll Results')
Expand Down Expand Up @@ -285,10 +275,10 @@ Using a Django form for poll choices
Now what does the FT say?:: 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): 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) self.assertEquals(len(choice_inputs), 3)
AssertionError: 0 != 3 AssertionError: 0 != 3


Expand Down Expand Up @@ -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 = Choice(poll=poll1, choice="Gardener's", votes=0)
choice2.save() choice2.save()


client = Client() response = self.client.get('/poll/%d/' % (poll1.id, ))
response = client.get('/poll/%d/' % (poll1.id, ))


# check we've passed in a form of the right type # check we've passed in a form of the right type
self.assertTrue(isinstance(response.context['form'], PollVoteForm)) self.assertTrue(isinstance(response.context['form'], PollVoteForm))
Expand Down Expand Up @@ -557,10 +546,10 @@ And now we have passination::
So let's ask the FTs again!:: 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): 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', 'Moderately awesome',
AssertionError: Lists differ: [u'Vote:', u'Very awesome', u'... != ['Very awesome', 'Quite awesom... AssertionError: Lists differ: [u'Vote:', u'Very awesome', u'... != ['Very awesome', 'Quite awesom...


Expand All @@ -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: 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 .. sourcecode:: python
:filename: mysite/fts/test_polls.py :filename: mysite/fts/tests.py


# He also sees a form, which offers him several choices. # He also sees a form, which offers him several choices.
# There are three options with radio buttons # There are three options with radio buttons
Expand Down Expand Up @@ -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: Well, a button is easy enough to add, although it may not do much... In the template:


.. sourcecode:: html+django .. sourcecode:: html+django
:filename: mysite/polls/templates/home.html :filename: mysite/polls/templates/poll.html


<html> <html>
<body> <body>
Expand All @@ -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!:: 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): 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') self.fail('TODO')
AssertionError: TODO AssertionError: TODO
---------------------------------------------------------------------- ----------------------------------------------------------------------
Expand Down

0 comments on commit 64ae7bd

Please sign in to comment.