@@ -131,7 +131,7 @@ FAIL: test_can_start_a_list_and_retrieve_it_later
131
131
Traceback (most recent call last):
132
132
File "...python-tdd-book/functional_tests.py", line 19, in
133
133
test_can_start_a_list_and_retrieve_it_later
134
- self.fail(' Finish the test!' )
134
+ self.fail(" Finish the test!" )
135
135
AssertionError: Finish the test!
136
136
137
137
---------------------------------------------------------------------
@@ -165,8 +165,8 @@ from selenium.webdriver.common.keys import Keys
165
165
import time
166
166
import unittest
167
167
168
- class NewVisitorTest(unittest.TestCase):
169
168
169
+ class NewVisitorTest(unittest.TestCase):
170
170
def setUp(self):
171
171
self.browser = webdriver.Firefox()
172
172
@@ -176,39 +176,34 @@ class NewVisitorTest(unittest.TestCase):
176
176
def test_can_start_a_list_and_retrieve_it_later(self):
177
177
# Edith has heard about a cool new online to-do app. She goes
178
178
# to check out its homepage
179
- self.browser.get(' http://localhost:8000' )
179
+ self.browser.get(" http://localhost:8000" )
180
180
181
181
# She notices the page title and header mention to-do lists
182
- self.assertIn(' To-Do' , self.browser.title)
183
- header_text = self.browser.find_element(By.TAG_NAME, 'h1' ).text #<1>
184
- self.assertIn(' To-Do' , header_text)
182
+ self.assertIn(" To-Do" , self.browser.title)
183
+ header_text = self.browser.find_element(By.TAG_NAME, "h1" ).text # <1>
184
+ self.assertIn(" To-Do" , header_text)
185
185
186
186
# She is invited to enter a to-do item straight away
187
- inputbox = self.browser.find_element(By.ID, 'id_new_item') #<1>
188
- self.assertEqual(
189
- inputbox.get_attribute('placeholder'),
190
- 'Enter a to-do item'
191
- )
187
+ inputbox = self.browser.find_element(By.ID, "id_new_item") # <1>
188
+ self.assertEqual(inputbox.get_attribute("placeholder"), "Enter a to-do item")
192
189
193
- # She types "Buy peacock feathers" into a text box (Edith's hobby
194
- # is tying fly-fishing lures)
195
- inputbox.send_keys(' Buy peacock feathers' ) #<2>
190
+ # She types "Buy peacock feathers" into a text box
191
+ # (Edith's hobby is tying fly-fishing lures)
192
+ inputbox.send_keys(" Buy peacock feathers" ) # <2>
196
193
197
194
# When she hits enter, the page updates, and now the page lists
198
195
# "1: Buy peacock feathers" as an item in a to-do list table
199
- inputbox.send_keys(Keys.ENTER) #<3>
200
- time.sleep(1) #<4>
196
+ inputbox.send_keys(Keys.ENTER) # <3>
197
+ time.sleep(1) # <4>
201
198
202
- table = self.browser.find_element(By.ID, 'id_list_table')
203
- rows = table.find_elements(By.TAG_NAME, 'tr') #<1>
204
- self.assertTrue(
205
- any(row.text == '1: Buy peacock feathers' for row in rows)
206
- )
199
+ table = self.browser.find_element(By.ID, "id_list_table")
200
+ rows = table.find_elements(By.TAG_NAME, "tr") # <1>
201
+ self.assertTrue(any(row.text == "1: Buy peacock feathers" for row in rows))
207
202
208
- # There is still a text box inviting her to add another item. She
209
- # enters "Use peacock feathers to make a fly" (Edith is very
210
- # methodical)
211
- self.fail(' Finish the test!' )
203
+ # There is still a text box inviting her to add another item.
204
+ # She enters "Use peacock feathers to make a fly"
205
+ # (Edith is very methodical)
206
+ self.fail(" Finish the test!" )
212
207
213
208
# The page updates again, and now shows both items on her list
214
209
[...]
@@ -371,14 +366,15 @@ https://docs.djangoproject.com/en/1.11/intro/tutorial03/#write-views-that-actual
371
366
Mmmh, syntax-highlighted... much nicer! Now to change our view function:
372
367
373
368
[role="sourcecode"]
374
- .lists/views.py
369
+ .lists/views.py (ch04l002)
375
370
====
376
371
[source,python]
377
372
----
378
373
from django.shortcuts import render
379
374
375
+
380
376
def home_page(request):
381
- return render(request, ' home.html' )
377
+ return render(request, " home.html" )
382
378
----
383
379
====
384
380
@@ -395,6 +391,7 @@ NOTE: Templates are a very powerful feature of Django's, and their main
395
391
why we use `render` and (later) +render_to​_string+ rather
396
392
than, say, manually reading the file from disk with the built-in `open` .
397
393
394
+
398
395
Let's see if it works:
399
396
400
397
[subs="specialcharacters,macros,callouts"]
@@ -410,7 +407,7 @@ Traceback (most recent call last):
410
407
response = home_page(request) <3>
411
408
^^^^^^^^^^^^^^^^^^
412
409
File ... python-tdd-book/lists/views.py", line 5, in home_page
413
- return render(request, ' home.html' ) <4>
410
+ return render(request, " home.html" ) <4>
414
411
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
415
412
File "... /django/shortcuts.py", line 24, in render
416
413
content = loader.render_to_string(template_name, context, request, using=using)
@@ -459,32 +456,32 @@ well. Belt and braces. Open it up and look for a variable called
459
456
# Application definition
460
457
461
458
INSTALLED_APPS = [
462
- ' django.contrib.admin' ,
463
- ' django.contrib.auth' ,
464
- ' django.contrib.contenttypes' ,
465
- ' django.contrib.sessions' ,
466
- ' django.contrib.messages' ,
467
- ' django.contrib.staticfiles' ,
468
- ' lists' ,
459
+ " django.contrib.admin" ,
460
+ " django.contrib.auth" ,
461
+ " django.contrib.contenttypes" ,
462
+ " django.contrib.sessions" ,
463
+ " django.contrib.messages" ,
464
+ " django.contrib.staticfiles" ,
465
+ " lists.apps.ListsConfig" ,
469
466
]
470
467
----
471
468
====
472
469
473
- //TODO: the new way of adding it would be lists.apps.ListConfig
474
-
475
470
476
- You can see there's lots of apps already in there by default. We just need to
477
- add ours, `lists`, to the bottom of the list. Don't forget the trailing
478
- comma--it may not be required, but one day you'll be really annoyed when you
479
- forget it and Python concatenates two strings on different lines...
471
+ You can see there's lots of apps already in there by default.
472
+ We just need to add ours, using the name `lists.app.ListsConfig`,
473
+ to the bottom of the list.
474
+ Don't forget the trailing comma--it may not be required,
475
+ but one day you'll be really annoyed when you forget it
476
+ and Python concatenates two strings on different lines...
480
477
481
478
Now we can try running the tests again:
482
479
483
480
[subs="specialcharacters,macros"]
484
481
----
485
482
$ pass:quotes[*python manage.py test*]
486
483
[...]
487
- self.assertTrue(html.endswith(' </html>' ))
484
+ self.assertTrue(html.endswith(" </html>" ))
488
485
AssertionError: False is not true
489
486
----
490
487
@@ -509,7 +506,7 @@ additional newline (`\n`) at the end. We can get them to pass like this:
509
506
====
510
507
[source,python]
511
508
----
512
- self.assertTrue(html.strip().endswith(' </html>' ))
509
+ self.assertTrue(html.strip().endswith(" </html>" ))
513
510
----
514
511
====
515
512
@@ -547,8 +544,8 @@ from django.template.loader import render_to_string
547
544
def test_home_page_returns_correct_html(self):
548
545
request = HttpRequest()
549
546
response = home_page(request)
550
- html = response.content.decode(' utf8' )
551
- expected_html = render_to_string(' home.html' )
547
+ html = response.content.decode(" utf8" )
548
+ expected_html = render_to_string(" home.html" )
552
549
self.assertEqual(html, expected_html)
553
550
----
554
551
====
@@ -567,15 +564,15 @@ Here's how it looks:
567
564
====
568
565
[source,python]
569
566
----
570
- def test_home_page_returns_correct_html(self):
571
- response = self.client.get('/' ) #<1>
567
+ def test_home_page_returns_correct_html(self):
568
+ response = self.client.get("/" ) # <1>
572
569
573
- html = response.content.decode(' utf8' ) #<2>
574
- self.assertTrue(html.startswith(' <html>' ))
575
- self.assertIn(' <title>To-Do lists</title>' , html)
576
- self.assertTrue(html.strip().endswith(' </html>' ))
570
+ html = response.content.decode(" utf8" ) # <2>
571
+ self.assertTrue(html.startswith(" <html>" ))
572
+ self.assertIn(" <title>To-Do lists</title>" , html)
573
+ self.assertTrue(html.strip().endswith(" </html>" ))
577
574
578
- self.assertTemplateUsed(response, ' home.html' ) #<3>
575
+ self.assertTemplateUsed(response, " home.html" ) # <3>
579
576
----
580
577
====
581
578
@@ -607,7 +604,7 @@ deliberately break it:
607
604
====
608
605
[source,python]
609
606
----
610
- self.assertTemplateUsed(response, ' wrong.html' )
607
+ self.assertTemplateUsed(response, " wrong.html" )
611
608
----
612
609
====
613
610
@@ -630,11 +627,11 @@ Django Test Client. We've combined two long-winded tests into one!
630
627
----
631
628
from django.test import TestCase
632
629
633
- class HomePageTest(TestCase):
634
630
631
+ class HomePageTest(TestCase):
635
632
def test_uses_home_template(self):
636
- response = self.client.get('/' )
637
- self.assertTemplateUsed(response, ' home.html' )
633
+ response = self.client.get("/" )
634
+ self.assertTemplateUsed(response, " home.html" )
638
635
----
639
636
====
640
637
@@ -671,11 +668,12 @@ On Refactoring
671
668
~~~~~~~~~~~~~~
672
669
673
670
674
- ((("unit tests", "refactoring in")))((("refactoring")))That
675
- was an absolutely trivial example of refactoring. But, as Kent Beck puts
676
- it in <<tddbe,'Test-Driven Development: By Example'>>, "Am I recommending that
677
- you actually work this way? No. I'm recommending that you be 'able' to work
678
- this way".
671
+ ((("unit tests", "refactoring in")))
672
+ ((("refactoring")))
673
+ That was an absolutely trivial example of refactoring.
674
+ But, as Kent Beck puts it in <<tddbe,'Test-Driven Development: By Example'>>,
675
+ "Am I recommending that you actually work this way? No.
676
+ I'm recommending that you be 'able' to work this way".
679
677
680
678
In fact, as I was writing this my first instinct was to dive in and change the
681
679
test first--make it use the `assertTemplateUsed` function straight away;
@@ -808,9 +806,9 @@ empty...
808
806
Now what does the FT say?
809
807
810
808
----
811
- File "functional_tests.py", line 43 , in
809
+ File "...python-tdd-book/ functional_tests.py", line 40 , in
812
810
test_can_start_a_list_and_retrieve_it_later
813
- any(row.text == ' 1: Buy peacock feathers' for row in rows)
811
+ self.assertTrue( any(row.text == " 1: Buy peacock feathers" for row in rows) )
814
812
AssertionError: False is not true
815
813
----
816
814
@@ -823,13 +821,13 @@ a custom error message as an argument to most `assertX` methods in `unittest`:
823
821
824
822
825
823
[role="sourcecode"]
826
- .functional_tests.py
824
+ .functional_tests.py (ch04l015)
827
825
====
828
826
[source,python]
829
827
----
830
828
self.assertTrue(
831
- any(row.text == ' 1: Buy peacock feathers' for row in rows),
832
- "New to-do item did not appear in table"
829
+ any(row.text == " 1: Buy peacock feathers" for row in rows),
830
+ "New to-do item did not appear in table",
833
831
)
834
832
----
835
833
====
0 commit comments