@@ -70,9 +70,9 @@ Now, running our FTs gives us a slightly cryptic, unexpected error:
70
70
$ pass:quotes[*python functional_tests.py*]
71
71
[...]
72
72
Traceback (most recent call last):
73
- File "...python-tdd-book/functional_tests.py", line 41 , in
73
+ File "...python-tdd-book/functional_tests.py", line 38 , in
74
74
test_can_start_a_list_and_retrieve_it_later
75
- table = self.browser.find_element(By.ID, ' id_list_table' )
75
+ table = self.browser.find_element(By.ID, " id_list_table" )
76
76
[...]
77
77
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate
78
78
element: [id="id_list_table"]
@@ -362,10 +362,11 @@ ERROR: test_uses_home_template
362
362
(lists.tests.HomePageTest.test_uses_home_template)
363
363
364
364
[...]
365
- File "...python-tdd-book/lists/views.py", line 5, in home_page
366
365
{"new_item_text": request.POST["item_text"]},
366
+ ~~~~~~~~~~~~^^^^^^^^^^^^^
367
367
[...]
368
368
django.utils.datastructures.MultiValueDictKeyError: 'item_text'
369
+
369
370
----
370
371
371
372
@@ -391,7 +392,7 @@ site manually, and we can get on with fixing it straight away. Here's how:
391
392
392
393
393
394
[role="sourcecode"]
394
- .lists/views.py
395
+ .lists/views.py (ch05l010)
395
396
====
396
397
[source,python]
397
398
----
@@ -436,7 +437,7 @@ improved error messages stay around to help debug any future errors:
436
437
----
437
438
self.assertTrue(
438
439
any(row.text == "1: Buy peacock feathers" for row in rows),
439
- f"New to-do item did not appear in table. Contents were:\n{table.text}" #<1>
440
+ f"New to-do item did not appear in table. Contents were:\n{table.text}", #<1>
440
441
)
441
442
----
442
443
====
@@ -541,13 +542,12 @@ check for adding a second item to the table (copy and paste is our friend), we
541
542
begin to see that our first cut solution really isn't going to, um, cut it:
542
543
543
544
[role="sourcecode"]
544
- .functional_tests.py
545
+ .functional_tests.py (ch05l014)
545
546
====
546
547
[source,python]
547
548
----
548
- def thing():
549
- # There is still a text box inviting her to add another item. She
550
- # enters "Use peacock feathers to make a fly"
549
+ # There is still a text box inviting her to add another item.
550
+ # She enters "Use peacock feathers to make a fly"
551
551
# (Edith is very methodical)
552
552
inputbox = self.browser.find_element(By.ID, "id_new_item")
553
553
inputbox.send_keys("Use peacock feathers to make a fly")
@@ -623,20 +623,18 @@ only methods that begin with `test_` will get run as tests, so you can use
623
623
other methods for your own purposes:
624
624
625
625
[role="sourcecode"]
626
- .functional_tests.py
626
+ .functional_tests.py (ch05l015)
627
627
====
628
628
[source,python]
629
629
----
630
630
def tearDown(self):
631
631
self.browser.quit()
632
632
633
-
634
633
def check_for_row_in_list_table(self, row_text):
635
- table = self.browser.find_element(By.ID, ' id_list_table' )
636
- rows = table.find_elements(By.TAG_NAME, 'tr' )
634
+ table = self.browser.find_element(By.ID, " id_list_table" )
635
+ rows = table.find_elements(By.TAG_NAME, "tr" )
637
636
self.assertIn(row_text, [row.text for row in rows])
638
637
639
-
640
638
def test_can_start_a_list_and_retrieve_it_later(self):
641
639
[...]
642
640
----
@@ -646,27 +644,27 @@ I like to put helper methods near the top of the class, between the `tearDown`
646
644
and the first test. Let's use it in the FT:
647
645
648
646
[role="sourcecode"]
649
- .functional_tests.py
647
+ .functional_tests.py (ch05l016)
650
648
====
651
649
[source,python]
652
650
----
653
651
# When she hits enter, the page updates, and now the page lists
654
652
# "1: Buy peacock feathers" as an item in a to-do list table
655
653
inputbox.send_keys(Keys.ENTER)
656
654
time.sleep(1)
657
- self.check_for_row_in_list_table(' 1: Buy peacock feathers' )
655
+ self.check_for_row_in_list_table(" 1: Buy peacock feathers" )
658
656
659
- # There is still a text box inviting her to add another item. She
660
- # enters "Use peacock feathers to make a fly" (Edith is very
661
- # methodical)
662
- inputbox = self.browser.find_element(By.ID, ' id_new_item' )
663
- inputbox.send_keys(' Use peacock feathers to make a fly' )
657
+ # There is still a text box inviting her to add another item.
658
+ # She enters "Use peacock feathers to make a fly"
659
+ # (Edith is very methodical)
660
+ inputbox = self.browser.find_element(By.ID, " id_new_item" )
661
+ inputbox.send_keys(" Use peacock feathers to make a fly" )
664
662
inputbox.send_keys(Keys.ENTER)
665
663
time.sleep(1)
666
664
667
665
# The page updates again, and now shows both items on her list
668
- self.check_for_row_in_list_table(' 1: Buy peacock feathers' )
669
- self.check_for_row_in_list_table(' 2: Use peacock feathers to make a fly' )
666
+ self.check_for_row_in_list_table(" 1: Buy peacock feathers" )
667
+ self.check_for_row_in_list_table(" 2: Use peacock feathers to make a fly" )
670
668
671
669
# Edith wonders whether the site will remember her list. Then she sees
672
670
[...]
@@ -713,31 +711,30 @@ how we want it to work.
713
711
Let's create a new class in 'lists/tests.py' :
714
712
715
713
[role="sourcecode"]
716
- .lists/tests.py
714
+ .lists/tests.py (ch05l017)
717
715
====
718
716
[source,python]
719
717
----
720
718
from lists.models import Item
721
719
[...]
722
720
723
721
class ItemModelTest(TestCase):
724
-
725
722
def test_saving_and_retrieving_items(self):
726
723
first_item = Item()
727
- first_item.text = ' The first (ever) list item'
724
+ first_item.text = " The first (ever) list item"
728
725
first_item.save()
729
726
730
727
second_item = Item()
731
- second_item.text = ' Item the second'
728
+ second_item.text = " Item the second"
732
729
second_item.save()
733
730
734
731
saved_items = Item.objects.all()
735
732
self.assertEqual(saved_items.count(), 2)
736
733
737
734
first_saved_item = saved_items[0]
738
735
second_saved_item = saved_items[1]
739
- self.assertEqual(first_saved_item.text, ' The first (ever) list item' )
740
- self.assertEqual(second_saved_item.text, ' Item the second' )
736
+ self.assertEqual(first_saved_item.text, " The first (ever) list item" )
737
+ self.assertEqual(second_saved_item.text, " Item the second" )
741
738
----
742
739
====
743
740
@@ -803,6 +800,7 @@ creating a class:
803
800
----
804
801
from django.db import models
805
802
803
+
806
804
class Item(object):
807
805
pass
808
806
----
@@ -829,6 +827,7 @@ model, we make it inherit from the `Model` class:
829
827
----
830
828
from django.db import models
831
829
830
+
832
831
class Item(models.Model):
833
832
pass
834
833
----
@@ -967,7 +966,7 @@ self-explanatory:
967
966
[source,python]
968
967
----
969
968
class Item(models.Model):
970
- text = models.TextField(default='' )
969
+ text = models.TextField(default="" )
971
970
----
972
971
====
973
972
@@ -1033,14 +1032,14 @@ response. We can do that by adding three new lines to the existing test called
1033
1032
[source,python]
1034
1033
----
1035
1034
def test_can_save_a_POST_request(self):
1036
- response = self.client.post('/' , data={' item_text': ' A new list item' })
1035
+ response = self.client.post("/" , data={" item_text": " A new list item" })
1037
1036
1038
- self.assertEqual(Item.objects.count(), 1) #<1>
1039
- new_item = Item.objects.first() #<2>
1040
- self.assertEqual(new_item.text, ' A new list item' ) #<3>
1037
+ self.assertEqual(Item.objects.count(), 1) # <1>
1038
+ new_item = Item.objects.first() # <2>
1039
+ self.assertEqual(new_item.text, " A new list item" ) # <3>
1041
1040
1042
- self.assertIn(' A new list item' , response.content.decode())
1043
- self.assertTemplateUsed(response, ' home.html' )
1041
+ self.assertIn(" A new list item" , response.content.decode())
1042
+ self.assertTemplateUsed(response, " home.html" )
1044
1043
----
1045
1044
====
1046
1045
@@ -1083,14 +1082,17 @@ Let's adjust our view:
1083
1082
from django.shortcuts import render
1084
1083
from lists.models import Item
1085
1084
1085
+
1086
1086
def home_page(request):
1087
1087
item = Item()
1088
- item.text = request.POST.get(' item_text', '' )
1088
+ item.text = request.POST.get(" item_text", "" )
1089
1089
item.save()
1090
1090
1091
- return render(request, 'home.html', {
1092
- 'new_item_text': request.POST.get('item_text', ''),
1093
- })
1091
+ return render(
1092
+ request,
1093
+ "home.html",
1094
+ {"new_item_text": request.POST.get("item_text", "")},
1095
+ )
1094
1096
----
1095
1097
====
1096
1098
@@ -1115,9 +1117,14 @@ refactoring:
1115
1117
====
1116
1118
[source,python]
1117
1119
----
1118
- return render(request, 'home.html', {
1119
- 'new_item_text': item.text
1120
- })
1120
+ [...]
1121
+ item.save()
1122
+
1123
+ return render(
1124
+ request,
1125
+ "home.html",
1126
+ {"new_item_text": item.text},
1127
+ )
1121
1128
----
1122
1129
====
1123
1130
@@ -1137,7 +1144,7 @@ test, but it's best to keep unit tests to testing one thing at a time, so let's
1137
1144
add a new one:
1138
1145
1139
1146
[role="sourcecode"]
1140
- .lists/tests.py
1147
+ .lists/tests.py (ch05l022)
1141
1148
====
1142
1149
[source,python]
1143
1150
----
@@ -1155,20 +1162,22 @@ quite a small change to the logic of the view, there are quite a few little
1155
1162
tweaks to the implementation in code:
1156
1163
1157
1164
[role="sourcecode"]
1158
- .lists/views.py
1165
+ .lists/views.py (ch05l023)
1159
1166
====
1160
1167
[source,python]
1161
1168
----
1162
1169
def home_page(request):
1163
- if request.method == ' POST' :
1164
- new_item_text = request.POST[' item_text' ] #<1>
1165
- Item.objects.create(text=new_item_text) #<2>
1170
+ if request.method == " POST" :
1171
+ new_item_text = request.POST[" item_text" ] # <1>
1172
+ Item.objects.create(text=new_item_text) # <2>
1166
1173
else:
1167
- new_item_text = '' #<1>
1174
+ new_item_text = "" # <1>
1168
1175
1169
- return render(request, 'home.html', {
1170
- 'new_item_text': new_item_text, #<1>
1171
- })
1176
+ return render(
1177
+ request,
1178
+ "home.html",
1179
+ {"new_item_text": new_item_text}, # <1>
1180
+ )
1172
1181
----
1173
1182
====
1174
1183
@@ -1239,12 +1248,13 @@ substantially:
1239
1248
from django.shortcuts import redirect, render
1240
1249
from lists.models import Item
1241
1250
1251
+
1242
1252
def home_page(request):
1243
- if request.method == ' POST' :
1244
- Item.objects.create(text=request.POST[' item_text' ])
1245
- return redirect('/' )
1253
+ if request.method == " POST" :
1254
+ Item.objects.create(text=request.POST[" item_text" ])
1255
+ return redirect("/" )
1246
1256
1247
- return render(request, ' home.html' )
1257
+ return render(request, " home.html" )
1248
1258
----
1249
1259
====
1250
1260
0 commit comments