dictionaries
preview
Here are the tests I have by the end of the chapter
1import unittest
2
3
4class TestDictionaries(unittest.TestCase):
5
6 def test_making_a_dictionary(self):
7 self.assertEqual(dict(), {})
8 self.assertEqual(dict(key='value'), {'key': 'value'})
9
10 def test_making_a_dictionary_w_none_as_a_key(self):
11 self.assertEqual({None: 'boom'}, {None: 'boom'})
12
13 def test_making_a_dictionary_w_a_boolean_as_a_key(self):
14 self.assertEqual(
15 {False: 'boom', True: 'bap'},
16 {False: 'boom', True: 'bap'}
17 )
18
19 def test_making_a_dictionary_w_a_number_as_a_key(self):
20 self.assertEqual(
21 {0: 'boom', 0.1: 'bap'},
22 {0: 'boom', 0.1: 'bap'}
23 )
24
25 def test_making_a_dictionary_w_a_tuple_as_a_key(self):
26 self.assertEqual(
27 {(0, 1): 'boom'},
28 {(0, 1): 'boom'}
29 )
30
31 def test_making_a_dictionary_w_a_list_as_a_key(self):
32 with self.assertRaises(TypeError):
33 {[3, 2, 1]: 'BOOM!!!'}
34
35 def test_making_a_dictionary_w_a_set_as_a_key(self):
36 with self.assertRaises(TypeError):
37 {{3, 2, 1}: 'BOOM!!!'}
38
39 def test_making_a_dictionary_w_a_dictionary_as_a_key(self):
40 a_dictionary = {'key': 'value'}
41 with self.assertRaises(TypeError):
42 {a_dictionary: 'BOOM!!!'}
43
44 def test_attributes_and_methods_of_dictionaries(self):
45 self.maxDiff = None
46 self.assertEqual(
47 dir(dict),
48 [
49 '__class__',
50 '__class_getitem__',
51 '__contains__',
52 '__delattr__',
53 '__delitem__',
54 '__dir__',
55 '__doc__',
56 '__eq__',
57 '__format__',
58 '__ge__',
59 '__getattribute__',
60 '__getitem__',
61 '__getstate__',
62 '__gt__',
63 '__hash__',
64 '__init__',
65 '__init_subclass__',
66 '__ior__',
67 '__iter__',
68 '__le__',
69 '__len__',
70 '__lt__',
71 '__ne__',
72 '__new__',
73 '__or__',
74 '__reduce__',
75 '__reduce_ex__',
76 '__repr__',
77 '__reversed__',
78 '__ror__',
79 '__setattr__',
80 '__setitem__',
81 '__sizeof__',
82 '__str__',
83 '__subclasshook__',
84 'clear',
85 'copy',
86 'fromkeys',
87 'get',
88 'items',
89 'keys',
90 'pop',
91 'popitem',
92 'setdefault',
93 'update',
94 'values'
95 ]
96 )
97
98 def test_clear_empties_a_dictionary(self):
99 a_dictionary = {'key': 'value'}
100 self.assertIsNone(a_dictionary.clear())
101 self.assertEqual(a_dictionary, {})
102
103 def test_copy_a_dictionary(self):
104 a_dictionary = {'key': 'value'}
105 self.assertEqual(
106 a_dictionary.copy(),
107 {'key': 'value'}
108 )
109
110 def test_fromkeys_makes_a_dictionary_from_an_iterable(self):
111 self.assertEqual(
112 dict.fromkeys((0, 1), 'default'),
113 {0: 'default', 1: 'default'}
114 )
115
116 def test_get_value_of_a_key_in_a_dictionary(self):
117 a_dictionary = {'key': 'value'}
118 self.assertEqual(
119 a_dictionary.get('not_in_dictionary', 'default'),
120 'default'
121 )
122 self.assertEqual(
123 a_dictionary.get('key', 'default'),
124 'value'
125 )
126
127 def test_items_returns_iterable_of_key_value_pairs_of_a_dictionary(self):
128 a_dictionary = {
129 'key1': 'value1',
130 'keyN': [0, 1, 2, 'n'],
131 }
132 self.assertEqual(
133 list(a_dictionary.items()),
134 [
135 ('key1', 'value1'),
136 ('keyN', [0, 1, 2, 'n']),
137 ]
138 )
139
140 def test_keys_of_a_dictionary(self):
141 a_dictionary = {
142 'key1': 'value1',
143 'keyN': [0, 1, 2, 'n'],
144 }
145 self.assertEqual(
146 list(a_dictionary.keys()),
147 ['key1', 'keyN']
148 )
149
150 def test_pop_removes_given_key_from_a_dictionary_and_returns_its_value(self):
151 a_dictionary = {'key': 'value'}
152
153 with self.assertRaises(KeyError):
154 a_dictionary.pop('not_in_dictionary')
155 self.assertEqual(
156 a_dictionary.pop('not_in_dictionary', 'default'),
157 'default'
158 )
159 self.assertEqual(
160 a_dictionary.pop('key', 'default'),
161 'value'
162 )
163 self.assertEqual(a_dictionary, {})
164
165 def test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary(self):
166 a_dictionary = {
167 'key1': 'value1',
168 'keyN': [0, 1, 2, 'n'],
169 }
170 self.assertEqual(
171 a_dictionary.popitem(),
172 ('keyN', [0, 1, 2, 'n'])
173 )
174 self.assertEqual(a_dictionary, {'key1': 'value1'})
175
176 def test_setdefault_adds_given_key_to_a_dictionary(self):
177 a_dictionary = {'key': 'value'}
178 self.assertEqual(
179 a_dictionary.setdefault('new_key', 'default'),
180 'default'
181 )
182 self.assertEqual(
183 a_dictionary.setdefault('key', 'default'),
184 'value'
185 )
186 self.assertEqual(
187 a_dictionary,
188 {
189 'key': 'value',
190 'new_key': 'default',
191 }
192 )
193
194 def test_update_a_dictionary(self):
195 a_dictionary = {'key': 'value'}
196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n']))
197 self.assertIsNone(a_dictionary.update(key='updated value'))
198 self.assertIsNone(a_dictionary.update({
199 'another_key': {0, 1, 2, 'n'}
200 }))
201 self.assertEqual(
202 a_dictionary,
203 {
204 'key': 'updated value',
205 'new_key': [0, 1, 2, 'n'],
206 'another_key': {0, 1, 2, 'n'},
207 }
208 )
209
210 def test_values_of_a_dictionary(self):
211 a_dictionary = {
212 'key1': 'value1',
213 'keyN': [0, 1, 2, 'n'],
214 }
215 self.assertEqual(
216 list(a_dictionary.values()),
217 [
218 'value1',
219 [0, 1, 2, 'n'],
220 ]
221 )
222
223 def test_key_error(self):
224 a_dictionary = {'key': 'value'}
225 self.assertEqual(a_dictionary['key'], 'value')
226
227 with self.assertRaises(KeyError):
228 a_dictionary['not_in_dictionary']
229 self.assertEqual(
230 a_dictionary.get('not_in_dictionary', 'default'),
231 'default'
232 )
233
234 with self.assertRaises(KeyError):
235 a_dictionary.pop('not_in_dictionary')
236 self.assertEqual(
237 a_dictionary.pop('not_in_dictionary', 'default'),
238 'default'
239 )
240
241 with self.assertRaises(KeyError):
242 {}.popitem()
243
244
245# Exceptions seen
246# AssertionError
247# TypeError
248# NameError
249# KeyError
questions about dictionaries
Here are questions you can answer after going through this chapter
start the project
I name this project
dictionariesI open
makePythonTdd.shormakePythonTdd.ps1in the editorTip
Here is a quick way to open
makePythonTdd.shormakePythonTdd.ps1if you are using Visual Studio Codecode makePythonTdd.shon Windows without Windows Subsystem for Linux use
code makePythonTdd.ps1I change everywhere I have
list_comprehensionsto the name of this project1#!/bin/bash 2mkdir dictionaries 3cd dictionaries 4mkdir src 5touch src/dictionaries.py 6mkdir tests 7touch tests/__init__.py 8 9echo "import unittest 10 11 12class TestDictionaries(unittest.TestCase): 13 14 def test_failure(self): 15 self.assertFalse(True) 16 17 18# Exceptions seen 19# AssertionError 20" > tests/test_dictionaries.pyAttention
on Windows without Windows Subsystem for Linux use
makePythonTdd.ps1NOTmakePythonTdd.sh1mkdir dictionaries 2cd dictionaries 3mkdir src 4New-Item src/dictionaries.py 5mkdir tests 6New-Item tests/__init__.py 7 8"import unittest 9 10 11class TestDictionaries(unittest.TestCase): 12 13 def test_failure(self): 14 self.assertFalse(True) 15 16# Exceptions seen 17# AssertionError 18" | Out-File tests/test_dictionaries.pyI run the program in the terminal
./makePythonTdd.shAttention
on Windows without Windows Subsystem for Linux use
makePythonTdd.ps1NOTmakePythonTdd.sh./makePythonTdd.ps1the terminal shows AssertionError
======================================= FAILURES ======================================= ____________________________ TestDictionaries.test_failure _____________________________ self = <tests.test_dictionaries.TestDictionaries testMethod=test_failure> def test_failure(self): > self.assertFalse(True) E AssertionError: True is not false tests/test_dictionaries.py:7: AssertionError =============================== short test summary info ================================ FAILED tests/test_dictionaries.py::TestDictionaries::test_failure - AssertionError: True is not false ================================== 1 failed in X.YZs ===================================I hold ctrl (Windows/Linux) or option or command (MacOS) on the keyboard and use the mouse to click on
tests/test_dictionaries.py:7to open it in the editor-
7 self.assertFalse(False)the test passes
test_making_a_dictionary
RED: make it fail
I change test_failure to test_making_a_dictionary then add an assertion
1import unittest
2
3
4class TestDictionaries(unittest.TestCase):
5
6 def test_making_a_dictionary(self):
7 self.assertEqual(dict(), None)
the terminal shows AssertionError
AssertionError: {} != None
GREEN: make it pass
I change the expectation to match
6 def test_making_a_dictionary(self):
7 self.assertEqual(dict(), {})
the test passes. These are two ways to make an empty dictionary
dict()curly braces -
{}
REFACTOR: make it better
I add another assertion, this time with input to make a dictionary with things in it
6 def test_making_a_dictionary(self): 7 self.assertEqual(dict(), {}) 8 self.assertEqual(dict(0), {})TypeError: 'int' object is not iterableI add TypeError to the list of Exceptions seen
11# Exceptions seen 12# AssertionError 13# TypeErrorI change the value given to
dict()to a tuple7 self.assertEqual(dict(), {}) 8 self.assertEqual(dict((0, 1)), {})TypeError: cannot convert dictionary update sequence element #0 to a sequenceI try a keyword argument
7 self.assertEqual(dict(), {}) 8 self.assertEqual(dict(key='value'), {})the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}I change the expectation to match the values in the terminal
8 self.assertEqual(dict(key='value'), {'key': 'value'})the test passes.
I know how to make a dictionary. I used a string as a key in this test. Next I test other Python basic data types to see which ones I can use as keys
test_making_a_dictionary_w_none_as_a_key
RED: make it fail
I add a test to see if I can use None as a key in a dictionary
8 self.assertEqual(dict(key='value'), {'key': 'value'})
9
10 def test_making_a_dictionary_w_none_as_a_key(self):
11 self.assertEqual({None: 'boom'}, {None: 'bap'})
12
13
14# Exceptions seen
the terminal shows AssertionError
AssertionError: {None: 'boom'} != {None: 'bap'}
GREEN: make it pass
I change 'bap' to 'boom'
11 self.assertEqual({None: 'boom'}, {None: 'boom'})
the test passes. I can use strings and None as keys in a dictionary
test_making_a_dictionary_w_a_boolean_as_a_key
RED: make it fail
I add a test to see if I can use a boolean as a key in a dictionary
10 def test_making_a_dictionary_w_none_as_a_key(self):
11 self.assertEqual({None: 'boom'}, {None: 'boom'})
12
13 def test_making_a_dictionary_w_a_boolean_as_a_key(self):
14 self.assertEqual({False: 'boom'}, {False: 'bap'})
15
16
17# Exceptions seen
the terminal shows AssertionError
AssertionError: {False: 'boom'} != {False: 'bap'}
GREEN: make it pass
I change 'bap' to 'boom'
14 self.assertEqual({False: 'boom'}, {False: 'boom'})
the tests passes. I can use False as a key in a dictionary
REFACTOR: make it better
I add an assertion for the other boolean
13 def test_making_a_dictionary_w_a_boolean_as_a_key(self):
14 self.assertEqual(
15 {False: 'boom', True: 'bap'},
16 {False: 'boom'}
17 )
the terminal shows AssertionError
AssertionError: {False: 'boom', True: 'bap'} != {False: 'boom'}
I add the new key-value pair to the expectation
14 self.assertEqual(
15 {False: 'boom', True: 'bap'},
16 {False: 'boom', True: 'bap'}
17 )
the test passes. I can use strings, booleans and None as keys in a dictionary
test_making_a_dictionary_w_a_number_as_a_key
RED: make it fail
I add a failing test to see if I can use a number as a key in a dictionary
16 {False: 'boom', True: 'bap'}
17 )
18
19 def test_making_a_dictionary_w_a_number_as_a_key(self):
20 self.assertEqual(
21 {0: 'boom'},
22 {0: 'bap'}
23 )
24
25
26# Exceptions seen
the terminal shows AssertionError
AssertionError: {0: 'boom'} != {0: 'bap'}
GREEN: make it pass
I change 'bap' to 'boom'
20 self.assertEqual(
21 {0: 'boom'},
22 {0: 'boom'}
23 )
the test passes. I can use an integer as a key in a dictionary
REFACTOR: make it better
I want to see if I can use a float as a key in a dictionary. I add a float to the dictionary
19 def test_making_a_dictionary_w_a_number_as_a_key(self):
20 self.assertEqual(
21 {0: 'boom', 0.1: 'bap'},
22 {0: 'boom'}
23 )
the terminal shows AssertionError
AssertionError: {0: 'boom', 0.1: 'bap'} != {0: 'boom'}
I add the new key-value pair to the expectation
20 self.assertEqual(
21 {0: 'boom', 0.1: 'bap'},
22 {0: 'boom', 0.1: 'bap'}
23 )
the test passes. I can use strings, numbers (floats and integers), booleans and None as keys in a dictionary
test_making_a_dictionary_w_a_tuple_as_a_key
RED: make it fail
I add a test to see if I can use a tuple (anything in parentheses (()), separated by a comma) as a key in a dictionary
20 self.assertEqual(
21 {0: 'boom', 0.1: 'bap'},
22 {0: 'boom', 0.1: 'bap'}
23 )
24
25 def test_making_a_dictionary_w_a_tuple_as_a_key(self):
26 self.assertEqual(
27 {(0, 1): 'boom'},
28 {(0, 1): 'bap'}
29 )
30
31
32# Exceptions seen
the terminal shows AssertionError
AssertionError: {(0, 1): 'boom'} != {(0, 1): 'bap'}
GREEN: make it pass
I change 'bap' to 'boom'
26 self.assertEqual(
27 {(0, 1): 'boom'},
28 {(0, 1): 'boom'}
29 )
the test passes. I can use tuples, strings, numbers (floats and integers), booleans and None as keys in a dictionary
test_making_a_dictionary_w_a_list_as_a_key
RED: make it fail
I add a test for lists (anything in square brackets ([]))
26 self.assertEqual(
27 {(0, 1): 'boom'},
28 {(0, 1): 'boom'}
29 )
30
31 def test_making_a_dictionary_w_a_list_as_a_key(self):
32 self.assertEqual(
33 {[0, 1]: 'boom'},
34 )
35
36
37# Exceptions seen
TypeError: unhashable type: 'list'
GREEN: make it pass
I remove the things around the new dictionary then change the key and value for fun
31 def test_making_a_dictionary_w_a_list_as_a_key(self): 32 33 {[3, 2, 1]: 'BOOM!!!'}I add assertRaises
31 def test_making_a_dictionary_w_a_list_as_a_key(self): 32 with self.assertRaises(TypeError): 33 {[3, 2, 1]: 'BOOM!!!'}the test passes. I cannot use a list as a key in a dictionary
test_making_a_dictionary_w_a_set_as_a_key
RED: make it fail
I add another test with a set (single items in curly braces ({})) as a key in a dictionary
32 with self.assertRaises(TypeError):
33 {[3, 2, 1]: 'BOOM!!!'}
34
35 def test_making_a_dictionary_w_a_set_as_a_key(self):
36 {{3, 2, 1}: 'BOOM!!!'}
37
38
39# Exceptions seen
TypeError: unhashable type: 'set'
GREEN: make it pass
I add assertRaises to handle the Exception
35 def test_making_a_dictionary_w_a_set_as_a_key(self):
36 with self.assertRaises(TypeError):
37 {{3, 2, 1}: 'BOOM!!!'}
the test is green again. I cannot use lists or sets as keys in a dictionary
test_making_a_dictionary_w_a_dictionary_as_a_key
RED: make it fail
I add another test, this time for a dictionary
36 with self.assertRaises(TypeError):
37 {[3, 2, 1]: 'BOOM!!!'}
38
39 def test_making_a_dictionary_w_a_dictionary_as_a_key(self):
40 a_dictionary = {'key': 'value'}
41 {a_dictionary: 'BOOM!!!'}
42
43
44# Exceptions seen
TypeError: unhashable type: 'dict'
GREEN: make it pass
I add assertRaises
39 def test_making_a_dictionary_w_a_dictionary_as_a_key(self):
40 a_dictionary = {'key': 'value'}
41 with self.assertRaises(TypeError):
42 {a_dictionary: 'BOOM!!!'}
43
44
45# Exceptions seen
the test passes. I cannot use dictionaries, sets or lists as keys in a dictionary. They are not hashable, which means they can change in their lifetime
test_attributes_and_methods_of_dictionaries
RED: make it fail
I add a new test with the dir built-in function to see the attributes and methods of dictionaries
41 with self.assertRaises(TypeError):
42 {a_dictionary: 'BOOM!!!'}
43
44 def test_attributes_and_methods_of_dictionaries(self):
45 self.assertEqual(
46 dir(dict),
47 []
48 )
49
50
51# Exceptions seen
the terminal shows AssertionError
AssertionError: Lists differ: ['__class__', '__class_getitem__', '__cont[530 chars]ues'] != []
It also gives me a message about how to show the full difference between the two lists
Diff is 720 characters long. Set self.maxDiff to None to see it.
unittest.TestCase.maxDiff is a class attribute that is used to set the maximum length of differences between 2 items that the terminal shows
GREEN: make it pass
I add maxDiff to the test
44 def test_attributes_and_methods_of_dictionaries(self): 45 self.maxDiff = None 46 self.assertEqual( 47 dir(dict), 48 [] 49 )the terminal shows the full difference between the two lists.
I copy (ctrl/command+c) and paste (ctrl/command+v) the expected values from the terminal then use find and replace to remove the extra characters
Note
results can be different because of the Python version.
44 def test_attributes_and_methods_of_dictionaries(self): 45 self.maxDiff = None 46 self.assertEqual( 47 dir(dict), 48 [ 49 '__class__', 50 '__class_getitem__', 51 '__contains__', 52 '__delattr__', 53 '__delitem__', 54 '__dir__', 55 '__doc__', 56 '__eq__', 57 '__format__', 58 '__ge__', 59 '__getattribute__', 60 '__getitem__', 61 '__getstate__', 62 '__gt__', 63 '__hash__', 64 '__init__', 65 '__init_subclass__', 66 '__ior__', 67 '__iter__', 68 '__le__', 69 '__len__', 70 '__lt__', 71 '__ne__', 72 '__new__', 73 '__or__', 74 '__reduce__', 75 '__reduce_ex__', 76 '__repr__', 77 '__reversed__', 78 '__ror__', 79 '__setattr__', 80 '__setitem__', 81 '__sizeof__', 82 '__str__', 83 '__subclasshook__', 84 'clear', 85 'copy', 86 'fromkeys', 87 'get', 88 'items', 89 'keys', 90 'pop', 91 'popitem', 92 'setdefault', 93 'update', 94 'values' 95 ] 96 )the test passes
I copy the names that do NOT have double underscores (__) and paste them below the test to make a TODO list that I use to test what I can do with dictionaries
93 'update', 94 'values' 95 ] 96 ) 97 98 99'clear', 100'copy', 101'fromkeys', 102'get', 103'items', 104'keys', 105'pop', 106'popitem', 107'setdefault', 108'update', 109'values' 110 111 112# Exceptions seenthe terminal still shows green
test_clear_empties_a_dictionary
RED: make it fail
I add a test for the first method
93 'update', 94 'values' 95 ] 96 ) 97 98 def test_clear(self): 99 a_dictionary = {'key': 'value'} 100 self.assertIsNone(a_dictionary.clear()) 101 102 103'clear',still green. The clear method returns None
I add an assertion to see what clear did to the dictionary
98 def test_clear(self): 99 a_dictionary = {'key': 'value'} 100 self.assertIsNone(a_dictionary.clear()) 101 self.assertEqual(a_dictionary, {'key': 'value'})the terminal shows AssertionError
AssertionError: {} != {'key': 'value'}the clear method emptied the dictionary, same as it does with lists
GREEN: make it pass
I change the values to match
98 def test_clear(self):
99 a_dictionary = {'key': 'value'}
100 self.assertIsNone(a_dictionary.clear())
101 self.assertEqual(a_dictionary, {})
the test passes
REFACTOR: make it better
I change the name of the test
98 def test_clear_empties_a_dictionary(self): 99 a_dictionary = {'key': 'value'} 100 self.assertIsNone(a_dictionary.clear()) 101 self.assertEqual(a_dictionary, {}) 102 103 104'clear',I remove clear from the TODO list
101 self.assertEqual(a_dictionary, {}) 102 103 104'copy', 105'fromkeys', 106'get', 107'items', 108'keys', 109'pop', 110'popitem', 111'setdefault', 112'update', 113'values'
test_copy_a_dictionary
RED: make it fail
I add a test for the copy method
101 self.assertEqual(a_dictionary, {})
102
103 def test_copy(self):
104 a_dictionary = {'key': 'value'}
105 self.assertIsNone(a_dictionary.copy())
106
107
108'copy',
109'fromkeys',
the terminal shows AssertionError
AssertionError: {'key': 'value'} is not None
this method returns a copy of the dictionary, same as with lists
GREEN: make it pass
I add the value to the assertion
103 def test_copy(self):
104 a_dictionary = {'key': 'value'}
105 self.assertIsNone(
106 a_dictionary.copy(),
107 {'key': 'value'}
108 )
the terminal shows AssertionError
AssertionError: {'key': 'value'} is not None : {'key': 'value'}
I change assertIsNone to assertEqual
103 def test_copy(self):
104 a_dictionary = {'key': 'value'}
105 self.assertEqual(
106 a_dictionary.copy(),
107 {'key': 'value'}
108 )
the test passes
REFACTOR: make it better
I change the name of the test
103 def test_copy_a_dictionary(self): 104 a_dictionary = {'key': 'value'} 105 self.assertEqual( 106 a_dictionary.copy(), 107 {'key': 'value'} 108 ) 109 110 111'copy', 112'fromkeys',I remove copy from the TODO list
105 self.assertEqual( 106 a_dictionary.copy(), 107 {'key': 'value'} 108 ) 109 110 111'fromkeys', 112'get', 113'items', 114'keys', 115'pop', 116'popitem', 117'setdefault', 118'update', 119'values'
test_fromkeys_makes_a_dictionary_from_an_iterable
RED: make it fail
I add a test for the next method from the TODO list
105 self.assertEqual(
106 a_dictionary.copy(),
107 {'key': 'value'}
108 )
109
110 def test_fromkeys(self):
111 a_dictionary = {'key': 'value'}
112 self.assertIsNone(a_dictionary.fromkeys())
113
114
115'fromkeys',
TypeError: fromkeys expected at least 1 argument, got 0
GREEN: make it pass
I pass a value to the call
110 def test_fromkeys(self): 111 a_dictionary = {'key': 'value'} 112 self.assertIsNone(a_dictionary.fromkeys(0))TypeError: 'int' object is not iterableI change the value to a tuple
112 self.assertIsNone(a_dictionary.fromkeys((0, 1)))the terminal shows AssertionError
AssertionError: {0: None, 1: None} is not Nonethe fromkeys method returns a dictionary that uses the values in the iterable as keys with default values of None. It reminds me of a list comprehension
I add the dictionary as an expectation
110 def test_fromkeys(self): 111 a_dictionary = {'key': 'value'} 112 self.assertIsNone( 113 a_dictionary.fromkeys((0, 1)), 114 {0: None, 1: None} 115 )the terminal shows AssertionError
AssertionError: {0: None, 1: None} is not None : {0: None, 1: None}I change assertIsNone to assertEqual
112 self.assertEqual( 113 a_dictionary.fromkeys((0, 1)), 114 {0: None, 1: None} 115 )the test passes
REFACTOR: make it better
I add another assert method to see what happened to
a_dictionary110 def test_fromkeys(self): 111 a_dictionary = {'key': 'value'} 112 self.assertEqual( 113 a_dictionary.fromkeys((0, 1)), 114 {0: None, 1: None} 115 ) 116 self.assertEqual(a_dictionary, {})the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}the dictionary did not change
I remove the last line I added
then change the call to fromkeys to use the dict class
110 def test_fromkeys(self): 111 a_dictionary = {'key': 'value'} 112 self.assertEqual( 113 dict.fromkeys((0, 1)), 114 {0: None, 1: None} 115 ) 116 117 118'fromkeys',the test is still green
I remove
a_dictionarysince it is not used110 def test_fromkeys(self): 111 self.assertEqual( 112 dict.fromkeys((0, 1)), 113 {0: None, 1: None} 114 ) 115 116 117'fromkeys',still green
the dictionary made with the fromkeys method has None as the default values. When I called the method without inputs the terminal showed TypeError
TypeError: fromkeys expected at least 1 argument, got 0I add a second input to the call to see what happens
111 self.assertEqual( 112 dict.fromkeys((0, 1), None), 113 {0: None, 1: None} 114 )the terminal still shows green
I change the second input expecting a failure
111 self.assertEqual( 112 dict.fromkeys((0, 1), 'default'), 113 {0: None, 1: None} 114 )the terminal shows AssertionError
AssertionError: {0: 'default', 1: 'default'} != {0: None, 1: None}I change the values in the expectation to match
111 self.assertEqual( 112 dict.fromkeys((0, 1), 'default'), 113 {0: 'default', 1: 'default'} 114 )the test is green again. This is like a dict comprehension because it made a dictionary using the items from the iterable as keys
I change the name of the test
110 def test_fromkeys_makes_a_dictionary_from_an_iterable(self): 111 self.assertEqual( 112 dict.fromkeys((0, 1), 'default'), 113 {0: 'default', 1: 'default'} 114 ) 115 116 117'fromkeys', 118'get',I remove fromkeys from the TODO list
111 self.assertEqual( 112 dict.fromkeys((0, 1), 'default'), 113 {0: 'default', 1: 'default'} 114 ) 115 116 117'get', 118'items', 119'keys', 120'pop', 121'popitem', 122'setdefault', 123'update', 124'values'
test_get_value_of_a_key_in_a_dictionary
RED: make it fail
I add a test for the get method
111 self.assertEqual(
112 dict.fromkeys((0, 1), 'default'),
113 {0: 'default', 1: 'default'}
114 )
115
116 def test_get(self):
117 a_dictionary = {'key': 'value'}
118 self.assertIsNone(a_dictionary.get())
119
120
121'get',
TypeError: get expected at least 1 argument, got 0
GREEN: make it pass
I add a value to the call
118 self.assertIsNone(a_dictionary.get(0))
the test passes
REFACTOR: make it better
the get method also expected at least 1 argument, I add None to the call
118 self.assertIsNone(a_dictionary.get(0, None))the terminal still shows green
I change the second argument expecting a failure
118 self.assertIsNone(a_dictionary.get(0, 'default'))the terminal shows AssertionError
AssertionError: 'default' is not NoneI add the expectation
116 def test_get(self): 117 a_dictionary = {'key': 'value'} 118 self.assertIsNone( 119 a_dictionary.get(0, 'default'), 120 'default' 121 )the terminal shows AssertionError
AssertionError: 'default' is not None : defaultI change assertIsNone to assertEqual
118 self.assertEqual( 119 a_dictionary.get(0, 'default'), 120 'default' 121 )the test passes
I change
0in the call to be clearer118 self.assertEqual( 119 a_dictionary.get('not_in_dictionary', 'default'), 120 'default' 121 )the test is still green
I want to see what happens when I use the get method with a key that is in the dictionary, I add another assertion
118 self.assertEqual( 119 a_dictionary.get('not_in_dictionary', 'default'), 120 'default' 121 ) 122 self.assertEqual( 123 a_dictionary.get('key', 'default'), 124 'default' 125 ) 126 127 128'get',the terminal shows AssertionError
AssertionError: 'value' != 'default'I get
'value'backI change the expectation to match
122 self.assertEqual( 123 a_dictionary.get('key', 'default'), 124 'value' 125 )the test passes
Note
The get method has a condition
when the key is NOT in the dictionary, it returns the default argument
when the key is in the dictionary, it returns its value
I change the name of the test
116 def test_get_value_of_a_key_in_a_dictionary(self): 117 a_dictionary = {'key': 'value'} 118 self.assertEqual( 119 a_dictionary.get('not_in_dictionary', 'default'), 120 'default' 121 ) 122 self.assertEqual( 123 a_dictionary.get('key', 'default'), 124 'value' 125 ) 126 127 128'get',the test is still green
I remove get from the TODO list
122 self.assertEqual( 123 a_dictionary.get('key', 'default'), 124 'value' 125 ) 126 127 128'items', 129'keys', 130'pop', 131'popitem', 132'setdefault', 133'update', 134'values'
I know how to get the value of a key that is in a dictionary
test_items_returns_iterable_of_key_value_pairs_of_a_dictionary
RED: make it fail
I add the next test from the TODO list
122 self.assertEqual(
123 a_dictionary.get('key', 'default'),
124 'value'
125 )
126
127 def test_items(self):
128 a_dictionary = {'key': 'value'}
129 self.assertIsNone(a_dictionary.items())
130
131
132'items',
the terminal shows AssertionError
AssertionError: dict_items([('key', 'value')]) is not None
GREEN: make it pass
I copy the
dict_itemsobject from the terminal and paste it as the expectation128 a_dictionary = {'key': 'value'} 129 self.assertIsNone( 130 a_dictionary.items(), 131 dict_items([('key', 'value')]) 132 )NameError: name 'dict_items' is not definedthis new object has a list and I know how to work with lists, just like dict_items
I add NameError to the list of Exceptions seen
145# Exceptions seen 146# AssertionError 147# TypeError 148# NameErrorI remove the stuff around the list
129 self.assertIsNone( 130 a_dictionary.items(), 131 [('key', 'value')] 132 )the terminal shows AssertionError
AssertionError: dict_items([('key', 'value')]) is not None : [('key', 'value')]I pass the call to the items method to
list()to see if it is iterable129 self.assertIsNone( 130 list(a_dictionary.items()), 131 [('key', 'value')] 132 )the terminal shows AssertionError
AssertionError: [('key', 'value')] is not None : [('key', 'value')]the values are the same
I change assertIsNone to assertEqual
129 self.assertEqual( 130 list(a_dictionary.items()), 131 [('key', 'value')] 132 )the test passes.
This works because the items method returns an iterable of the key-value pairs of the dictionary. The dict_items object is iterable
REFACTOR: make it better
I add another key-value pair to the dictionary to see what the method does when there is more than one
127 def test_items(self): 128 a_dictionary = { 129 'key1': 'value1', 130 'keyN': [0, 1, 2, 'n'], 131 } 132 self.assertEqual( 133 list(a_dictionary.items()), 134 [('key', 'value')] 135 ) 136 137 138'items',the terminal shows AssertionError
AssertionError: Lists differ: [('key1', 'value1'), ('keyN', [0, 1, 2, 'n'])] != [('key', 'value')]I change the expectation to match
132 self.assertEqual( 133 list(a_dictionary.items()), 134 [ 135 ('key1', 'value1'), 136 ('keyN', [0, 1, 2, 'n']), 137 ] 138 )the test passes
I change the name of the test
127 def test_items_returns_iterable_of_key_value_pairs_of_a_dictionary(self): 128 a_dictionary = { 129 'key1': 'value1', 130 'keyN': [0, 1, 2, 'n'], 131 } 132 self.assertEqual( 133 list(a_dictionary.items()), 134 [ 135 ('key1', 'value1'), 136 ('keyN', [0, 1, 2, 'n']), 137 ] 138 ) 139 140 141'items',I remove items from the TODO list
132 self.assertEqual( 133 list(a_dictionary.items()), 134 [ 135 ('key1', 'value1'), 136 ('keyN', [0, 1, 2, 'n']), 137 ] 138 ) 139 140 141'keys', 142'pop', 143'popitem', 144'setdefault', 145'update', 146'values'all tests are still passing
I know how to look at the key-value pairs in a dictionary as a list of tuples
test_keys_of_a_dictionary
RED: make it fail
I add a new test
132 self.assertEqual(
133 list(a_dictionary.items()),
134 [
135 ('key1', 'value1'),
136 ('keyN', [0, 1, 2, 'n']),
137 ]
138 )
139
140 def test_keys(self):
141 a_dictionary = {'key': 'value'}
142 self.assertIsNone(a_dictionary.keys())
143
144
145'keys',
the terminal shows AssertionError
AssertionError: dict_keys(['key']) is not None
this looks like the error in test_items_returns_iterable_of_key_value_pairs_of_a_dictionary
GREEN: make it pass
I copy the
dict_keysobject from the terminal and paste it as the expectation140 def test_keys(self): 141 a_dictionary = {'key': 'value'} 142 self.assertIsNone( 143 a_dictionary.keys(), 144 dict_keys(['key']) 145 )NameError: name 'dict_keys' is not definedI use the list in the
dict_keysobject as the expectation140 def test_keys(self): 141 a_dictionary = {'key': 'value'} 142 self.assertIsNone( 143 a_dictionary.keys(), 144 ['key'] 145 )the terminal shows AssertionError
AssertionError: dict_keys(['key']) is not None : ['key']I pass the call to the keys method to
list()to see ifdict_keysis iterable142 self.assertIsNone( 143 list(a_dictionary.keys()), 144 ['key'] 145 )the terminal shows AssertionError
AssertionError: ['key'] is not None : ['key']I change assertIsNone to assertEqual
142 self.assertEqual( 143 list(a_dictionary.keys()), 144 ['key'] 145 )the test passes
REFACTOR: make it better
I add another key-value pair to the dictionary to see what the keys method returns when there are multiple
140 def test_keys(self): 141 a_dictionary = { 142 'key1': 'value1', 143 'keyN': [0, 1, 2, 'n'], 144 } 145 self.assertEqual( 146 list(a_dictionary.keys()), 147 ['key'] 148 )the terminal shows AssertionError
AssertionError: Lists differ: ['key1', 'keyN'] != ['key']I change the expectation to match
145 self.assertEqual( 146 list(a_dictionary.keys()), 147 ['key1', 'keyN'] 148 )the test passes
I change the name of the test
140 def test_keys_of_a_dictionary(self): 141 a_dictionary = { 142 'key1': 'value1', 143 'keyN': [0, 1, 2, 'n'], 144 } 145 self.assertEqual( 146 list(a_dictionary.keys()), 147 ['key1', 'keyN'] 148 ) 149 150 151'keys',I remove keys from the TODO list
145 self.assertEqual( 146 list(a_dictionary.keys()), 147 ['key1', 'keyN'] 148 ) 149 150 151'pop', 152'popitem', 153'setdefault', 154'update', 155'values'
test_pop_removes_given_key_from_a_dictionary_and_returns_its_value
RED: make it fail
I wonder if the pop method of dictionaries behaves the same way as the pop method of lists. I add a test for it
145 self.assertEqual(
146 list(a_dictionary.keys()),
147 ['key1', 'keyN']
148 )
149
150 def test_pop(self):
151 a_dictionary = {'key': 'value'}
152 self.assertIsNone(a_dictionary.pop())
153
154
155'pop',
TypeError: pop expected at least 1 argument, got 0
this pop method is different from the pop method of lists
GREEN: make it pass
I pass a value to the call
152 self.assertIsNone(a_dictionary.pop(0))KeyError: 0I add KeyError to the list of Exceptions seen
162# Exceptions seen 163# AssertionError 164# TypeError 165# NameError 166# KeyErrorI remove the things around the call in the test and change the value given to be clearer
150 def test_pop(self): 151 a_dictionary = {'key': 'value'} 152 a_dictionary.pop('not_in_dictionary')KeyError: 'not in dictionary'I add assertRaises
150 def test_pop(self): 151 a_dictionary = {'key': 'value'} 152 153 with self.assertRaises(KeyError): 154 a_dictionary.pop('not_in_dictionary')the test passes. When I call the pop method with a key that is not in the dictionary it raises KeyError
REFACTOR: make it better
When I called the pop method without input, the terminal showed TypeError
TypeError: pop expected at least 1 argument, got 0I add another assertion to see what happens when I call it with 2 arguments
153 with self.assertRaises(KeyError): 154 a_dictionary.pop('not_in_dictionary') 155 self.assertIsNone(a_dictionary.pop('not_in_dictionary', None))the test is still green
I change the second argument, expecting a failure
155 self.assertIsNone(a_dictionary.pop('not_in_dictionary', 'default'))the terminal shows AssertionError
AssertionError: 'default' is not NoneI add the expectation
155 self.assertIsNone( 156 a_dictionary.pop('not_in_dictionary', 'default'), 157 'default' 158 )the terminal shows AssertionError
AssertionError: 'default' is not None : defaultI change assertIsNone to assertEqual
155 self.assertEqual( 156 a_dictionary.pop('not_in_dictionary', 'default'), 157 'default' 158 )the test passes
I add another assertion to see what happens when I call the pop method with a key that is in the dictionary
155 self.assertEqual( 156 a_dictionary.pop('not_in_dictionary', 'default'), 157 'default' 158 ) 159 self.assertEqual( 160 a_dictionary.pop('key', 'default'), 161 'default' 162 )the terminal shows AssertionError
AssertionError: 'value' != 'default'I get
'value'back. The pop method returns the value of the given key from the dictionaryI change the expectation to match
159 self.assertEqual( 160 a_dictionary.pop('key', 'default'), 161 'value' 162 )the test passes
I add another assertion to see what the pop method did to the dictionary
159 self.assertEqual( 160 a_dictionary.pop('key', 'default'), 161 'value' 162 ) 163 self.assertEqual(a_dictionary, {'key': 'value'})the terminal shows AssertionError
AssertionError: {} != {'key': 'value'}the pop method removes the key-value pair and returns the value of the given key from the dictionary
I change the expectation to match
163 self.assertEqual(a_dictionary, {})the test passes
I change the name of the test
150 def test_pop_removes_given_key_from_a_dictionary_and_returns_its_value(self): 151 a_dictionary = {'key': 'value'} 152 153 with self.assertRaises(KeyError): 154 a_dictionary.pop('not_in_dictionary') 155 self.assertEqual( 156 a_dictionary.pop('not_in_dictionary', 'default'), 157 'default' 158 ) 159 self.assertEqual( 160 a_dictionary.pop('key', 'default'), 161 'value' 162 ) 163 self.assertEqual(a_dictionary, {}) 164 165 166'pop',I remove pop from the TODO list
163 self.assertEqual(a_dictionary, {}) 164 165 166'popitem', 167'setdefault', 168'update', 169'values'
test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary
RED: make it fail
I add a failing test for the next item in the TODO list
163 self.assertEqual(a_dictionary, {})
164
165 def test_popitem(self):
166 a_dictionary = {'key': 'value'}
167 self.assertIsNone(a_dictionary.popitem())
168
169
170'popitem',
the terminal shows AssertionError
AssertionError: ('key', 'value') is not None
the popitem method returns the key-value pair in the dictionary as a tuple
GREEN: make it pass
I add the value from the terminal as the expectation
166 a_dictionary = {'key': 'value'}
167 self.assertIsNone(
168 a_dictionary.popitem(),
169 ('key', 'value')
170 )
the terminal shows AssertionError
AssertionError: ('key', 'value') is not None : ('key', 'value')
I change assertIsNone to assertEqual
167 self.assertEqual(
168 a_dictionary.popitem(),
169 ('key', 'value')
170 )
the test passes
REFACTOR: make it better
I add another assertion to see what the popitem method did to the dictionary
167 self.assertEqual( 168 a_dictionary.popitem(), 169 ('key', 'value') 170 ) 171 self.assertEqual(a_dictionary, {'key': 'value'})the terminal shows AssertionError
AssertionError: {} != {'key': 'value'}popitem removes and returns the key-value pair from the dictionary
I change the value to match
171 self.assertEqual(a_dictionary, {})the test passes
this operation does not take input, I change the dictionary to see what happens
165 def test_popitem(self): 166 a_dictionary = { 167 'key1': 'value1', 168 'keyN': [0, 1, 2, 'n'], 169 } 170 self.assertEqual( 171 a_dictionary.popitem(), 172 ('key', 'value') 173 ) 174 self.assertEqual(a_dictionary, {})the terminal shows AssertionError
AssertionError: Tuples differ: ('keyN', [0, 1, 2, 'n']) != ('key', 'value')popitem removes and returns the last key-value pair from a dictionary
I change the expectation in the first assertEqual to match
170 self.assertEqual( 171 a_dictionary.popitem(), 172 ('keyN', [0, 1, 2, 'n']) 173 )the terminal shows AssertionError
AssertionError: {'key1': 'value1'} != {'key': 'value'}I change the value in the second assertEqual to match
174 self.assertEqual(a_dictionary, {'key1': 'value1'})the test passes
I change the name of the test
165 def test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary(self): 166 a_dictionary = { 167 'key1': 'value1', 168 'keyN': [0, 1, 2, 'n'], 169 } 170 self.assertEqual( 171 a_dictionary.popitem(), 172 ('keyN', [0, 1, 2, 'n']) 173 ) 174 self.assertEqual(a_dictionary, {'key1': 'value1'}) 175 176 177'popitem',I remove popitem from the TODO list
174 self.assertEqual(a_dictionary, {'key1': 'value1'}) 175 176 177'setdefault', 178'update', 179'values'
I know how to remove the last key-value pair from a dictionary
test_setdefault_adds_given_key_to_a_dictionary
RED: make it fail
I add a test for the setdefault method
174 self.assertEqual(a_dictionary, {'key1': 'value1'})
175
176 def test_setdefault(self):
177 a_dictionary = {'key': 'value'}
178 self.assertIsNone(a_dictionary.setdefault())
179
180
181'setdefault',
TypeError: setdefault expected at least 1 argument, got 0
GREEN: make it pass
I pass a value in the call
178 self.assertIsNone(a_dictionary.setdefault(0))
the test passes
REFACTOR: make it better
The error message showed that the method expects at least 1 argument, I add a second argument
178 self.assertIsNone(a_dictionary.setdefault(0, None))the test is still green
I change the second argument expecting a failure
178 self.assertIsNone(a_dictionary.setdefault(0, 'default'))the terminal shows AssertionError
AssertionError: 'default' is not NoneI add the expectation
177 a_dictionary = {'key': 'value'} 178 self.assertIsNone( 179 a_dictionary.setdefault(0, 'default'), 180 'default' 181 )the terminal shows AssertionError
AssertionError: 'default' is not None : defaultI change assertIsNone to assertEqual
178 self.assertEqual( 179 a_dictionary.setdefault(0, 'default'), 180 'default' 181 )the test passes
I add an assertion to see what setdefault did to the dictionary
178 self.assertEqual( 179 a_dictionary.setdefault(0, 'default'), 180 'default' 181 ) 182 self.assertEqual(a_dictionary, {'key': 'value'})the terminal shows AssertionError
AssertionError: {'key': 'value', 0: 'default'} != {'key': 'value'}setdefault adds the given key to the dictionary with the default value and returns the default value
I change the expectation to match
176 def test_setdefault(self): 177 a_dictionary = {'key': 'value'} 178 self.assertEqual( 179 a_dictionary.setdefault(0, 'default'), 180 'default' 181 ) 182 self.assertEqual( 183 a_dictionary, 184 { 185 'key': 'value', 186 0: 'default', 187 } 188 )the test passes
I change the
0given in the call to the setdefault method be clearer178 self.assertEqual( 179 a_dictionary.setdefault('new_key', 'default'), 180 'default' 181 )the terminal shows AssertionError
AssertionError: {'key': 'value', 'new_key': 'default'} != {'key': 'value', 0: 'default'}I change the expectation to match
181 self.assertEqual( 182 a_dictionary, 183 { 184 'key': 'value', 185 'new_key': 'default', 186 } 187 )the test is green again
I add an assertion to see what happens when I use setdefault with a key that is already in the dictionary
176 def test_setdefault(self): 177 a_dictionary = {'key': 'value'} 178 self.assertEqual( 179 a_dictionary.setdefault('new_key', 'default'), 180 'default' 181 ) 182 self.assertEqual( 183 a_dictionary.setdefault('key', 'default'), 184 'default' 185 ) 186 self.assertEqual( 187 a_dictionary, 188 { 189 'key': 'value', 190 'new_key': 'default', 191 } 192 )the terminal shows AssertionError
AssertionError: 'value' != 'default'setdefault returns the value for a key in a dictionary when the key is in the dictionary
I change the expectation to match
182 self.assertEqual( 183 a_dictionary.setdefault('key', 'default'), 184 'value' 185 )the test passes
Note
setdefault has a condition
when the key is NOT in the dictionary it adds it with a default value of None and returns None
when the key is NOT in the dictionary and I call setdefault with a second argument, it adds the key to the dictionary with the second argument as the value and returns the second argument
when the key is in the dictionary it returns its value from the dictionary
I change the name of the test
176 def test_setdefault_adds_given_key_to_a_dictionary(self): 177 a_dictionary = {'key': 'value'} 178 self.assertEqual( 179 a_dictionary.setdefault('new_key', 'default'), 180 'default' 181 ) 182 self.assertEqual( 183 a_dictionary.setdefault('key', 'default'), 184 'value' 185 ) 186 self.assertEqual( 187 a_dictionary, 188 { 189 'key': 'value', 190 'new_key': 'default', 191 } 192 ) 193 194 195'setdefault',I remove setdefault from the TODO list
186 self.assertEqual( 187 a_dictionary, 188 { 189 'key': 'value', 190 'new_key': 'default', 191 } 192 ) 193 194 195'update', 196'values'
I know how to add a key with a default value to a dictionary
test_update_a_dictionary
RED: make it fail
I add a test for the next method from the TODO list
186 self.assertEqual( 187 a_dictionary, 188 { 189 'key': 'value', 190 'new_key': 'default', 191 } 192 ) 193 194 def test_update(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update()) 197 198 199'update',the test is green. The update method returns None
I add an assertion to see what it did to the dictionary
194 def test_update(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update()) 197 self.assertEqual(a_dictionary, {})the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}the dictionary did not change
GREEN: make it pass
I change the values in the expectation to match the terminal
197 self.assertEqual(a_dictionary, {'key': 'value'})
the test passes
REFACTOR: make it better
I add a value to the call to the update method to see what happens
194 def test_update(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update(0)) 197 self.assertEqual(a_dictionary, {'key': 'value'})TypeError: 'int' object is not iterableI change the value to a tuple
196 self.assertIsNone(a_dictionary.update((0, 1)))TypeError: cannot convert dictionary update sequence element #0 to a sequenceI had the same error message when I tried to make a dictionary with things in it
I try a keyword argument
196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n']))the terminal shows AssertionError
AssertionError: {'key': 'value', 'new_key': [0, 1, 2, 'n']} != {'key': 'value'}I add the new key-value pair to the expectation
196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n'])) 197 self.assertEqual( 198 a_dictionary, 199 { 200 'key': 'value', 201 'new_key': [0, 1, 2, 'n'], 202 } 203 )the test passes
I add an assertion to see what happens when I give a key that is already in the dictionary
194 def test_update(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n'])) 197 self.assertIsNone(a_dictionary.update(key='updated value')) 198 self.assertEqual(the terminal shows AssertionError
AssertionError: {'key': 'updated value', 'new_key': [0, 1, 2, 'n']} != {'key': 'value', 'new_key': [0, 1, 2, 'n']}the update method changes the value for a key that is already in a dictionary
I change the expectation to match
198 self.assertEqual( 199 a_dictionary, 200 { 201 'key': 'updated value', 202 'new_key': [0, 1, 2, 'n'], 203 } 204 )the test passes
since the update method takes keyword arguments, I can give it a dictionary as input. I add another assertion
194 def test_update(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n'])) 197 self.assertIsNone(a_dictionary.update(key='updated value')) 198 self.assertIsNone(a_dictionary.update( 199 {'another_key': {0, 1, 2, 'n'}} 200 )) 201 self.assertEqual(the terminal shows AssertionError
AssertionError: {'key[14 chars]lue', 'new_key': [0, 1, 2, 'n'], 'another_key': {0, 1, 2, 'n'}} != {'key[14 chars]lue', 'new_key': [0, 1, 2, 'n']}I can use the update method to add key-value pairs from one dictionary to another
I change the expectation in the assertEqual to match
201 self.assertEqual( 202 a_dictionary, 203 { 204 'key': 'updated value', 205 'new_key': [0, 1, 2, 'n'], 206 'another_key': {0, 1, 2, 'n'}, 207 } 208 )the test passes
I change the name of the test
194 def test_update_a_dictionary(self): 195 a_dictionary = {'key': 'value'} 196 self.assertIsNone(a_dictionary.update(new_key=[0, 1, 2, 'n'])) 197 self.assertIsNone(a_dictionary.update(key='updated value')) 198 self.assertIsNone(a_dictionary.update( 199 {'another_key': {0, 1, 2, 'n'}} 200 )) 201 self.assertEqual( 202 a_dictionary, 203 { 204 'key': 'updated value', 205 'new_key': [0, 1, 2, 'n'], 206 'another_key': {0, 1, 2, 'n'} 207 } 208 ) 209 210 211'update',the test is still green
I remove update from the TODO list
201 self.assertEqual( 202 a_dictionary, 203 { 204 'key': 'updated value', 205 'new_key': [0, 1, 2, 'n'], 206 'another_key': {0, 1, 2, 'n'} 207 } 208 ) 209 210 211'values'
I know how to add key-value pairs from one dictionary to another
test_values_of_a_dictionary
RED: make it fail
I add a test for the last method in my TODO list
201 self.assertEqual(
202 a_dictionary,
203 {
204 'key': 'updated value',
205 'new_key': [0, 1, 2, 'n'],
206 'another_key': {0, 1, 2, 'n'},
207 }
208 )
209
210 def test_values(self):
211 a_dictionary = {'key': 'value'}
212 self.assertIsNone(a_dictionary.values())
213
214
215'values'
the terminal shows AssertionError
AssertionError: dict_values(['value']) is not None
this is like test_items_returns_iterable_of_key_value_pairs_of_a_dictionary and test_keys_of_a_dictionary
GREEN: make it pass
I add the expected value
210 def test_values(self): 211 a_dictionary = {'key': 'value'} 212 self.assertIsNone( 213 a_dictionary.values, 214 dict_values(['value']) 215 )NameError: name 'dict_values' is not definedI remove the things around the list in the
dict_valuesobject212 self.assertIsNone( 213 a_dictionary.values(), 214 ['value'] 215 )the terminal shows AssertionError
AssertionError: dict_values(['value']) is not None : ['value']I use
list()to see ifdict_valuesis iterable212 self.assertIsNone( 213 list(a_dictionary.values()), 214 ['value'] 215 )the terminal shows AssertionError
AssertionError: ['value'] is not None : ['value']I change assertIsNone to assertEqual
212 self.assertEqual( 213 list(a_dictionary.values()), 214 ['value'] 215 )the test passes
REFACTOR: make it better
I change the dictionary to see what happens when it has more than one key-value pair
210 def test_values(self): 211 a_dictionary = { 212 'key1': 'value1', 213 'keyN': [0, 1, 2, 'n'], 214 } 215 self.assertEqual( 216 list(a_dictionary.values()), 217 ['value'] 218 )the terminal shows AssertionError
AssertionError: Lists differ: ['value1', [0, 1, 2, 'n']] != ['value']I change the values in the expectation
215 self.assertEqual( 216 list(a_dictionary.values()), 217 [ 218 'value1', 219 [0, 1, 2, 'n'], 220 ] 221 )the test passes
I change the name of the test
210 def test_values_of_a_dictionary(self): 211 a_dictionary = { 212 'key1': 'value1', 213 'keyN': [0, 1, 2, 'n'], 214 } 215 self.assertEqual( 216 list(a_dictionary.values()), 217 [ 218 'value1', 219 [0, 1, 2, 'n'], 220 ] 221 ) 222 223 224'values'I remove values from the TODO list
215 self.assertEqual( 216 list(a_dictionary.values()), 217 [ 218 'value1', 219 [0, 1, 2, 'n'] 220 ] 221 ) 222 223 224# Exceptions seen
test_key_error
KeyError is an important Exception to know when working with a dictionary. It happened earlier in my test for the pop method
RED: make it fail
I add a test for getting the value of a key that is in a dictionary
215 self.assertEqual(
216 list(a_dictionary.values()),
217 [
218 'value1',
219 [0, 1, 2, 'n']
220 ]
221 )
222
223 def test_key_error(self):
224 a_dictionary = {'key': 'value'}
225 self.assertEqual(a_dictionary['key'], '')
226
227
228# Exceptions seen
the terminal shows AssertionError
AssertionError: 'value' != ''
I get 'value' back. I can get the value for a key in a dictionary by giving the key in [], the same way I can get items from a list by giving the index in []
GREEN: make it pass
I change the value in the expectation to match the terminal
225 self.assertEqual(a_dictionary['key'], 'value')
the test passes
REFACTOR: make it better
I add another assertion, this time for a key that is not in the dictionary
225 self.assertEqual(a_dictionary['key'], 'value') 226 self.assertEqual(a_dictionary['not_in_dictionary'])KeyError: 'not_in_dictionary'I change the assertEqual to assertRaises
225 self.assertEqual(a_dictionary['key'], 'value') 226 227 with self.assertRaises(KeyError): 228 a_dictionary['not_in_dictionary']the test passes
I can use the get method when I do not want to get KeyError with a key that is not in a dictionary
227 with self.assertRaises(KeyError): 228 a_dictionary['not_in_dictionary'] 229 self.assertEqual( 230 a_dictionary.get('not_in_dictionary', 'default'), 231 '' 232 )the terminal shows AssertionError
AssertionError: 'default' != ''I change the expectation
229 self.assertEqual( 230 a_dictionary.get('not_in_dictionary', 'default'), 231 'default' 232 )the test passes. This is a repetition of test_get_value_of_a_key_in_a_dictionary, here is another one
The pop method raised KeyError when I gave it a key that was not in the dictionary, I add a failing line for it
229 self.assertEqual( 230 a_dictionary.get('not_in_dictionary', 'default'), 231 'default' 232 ) 233 234 a_dictionary.pop('not_in_dictionary')KeyError: 'not_in_dictionary'I add assertRaises
229 self.assertEqual( 230 a_dictionary.get('not_in_dictionary', 'default'), 231 'default' 232 ) 233 234 with self.assertRaises(KeyError): 235 a_dictionary.pop('not_in_dictionary')the test passes
I can give a second argument when I do not want the pop method to raise KeyError when the key is not in the dictionary. I add an assertion
234 with self.assertRaises(KeyError): 235 a_dictionary.pop('not_in_dictionary') 236 self.assertEqual( 237 a_dictionary.pop('not_in_dictionary', 'default'), 238 '' 239 )the terminal shows AssertionError
AssertionError: 'default' != ''I change the expectation to match
236 self.assertEqual( 237 a_dictionary.pop('not_in_dictionary', 'default'), 238 'default' 239 )the test passes
The popitem method also raises KeyError when called on an empty dictionary
236 self.assertEqual( 237 a_dictionary.pop('not_in_dictionary', 'default'), 238 'default' 239 ) 240 241 {}.popitem()KeyError: 'popitem(): dictionary is empty'I cannot remove the last key-value pair from a dictionary that has no key-value pairs
I add assertRaises
223 def test_key_error(self): 224 a_dictionary = {'key': 'value'} 225 self.assertEqual(a_dictionary['key'], 'value') 226 227 with self.assertRaises(KeyError): 228 a_dictionary['not_in_dictionary'] 229 self.assertEqual( 230 a_dictionary.get('not_in_dictionary', 'default'), 231 'default' 232 ) 233 234 with self.assertRaises(KeyError): 235 a_dictionary.pop('not_in_dictionary') 236 self.assertEqual( 237 a_dictionary.pop('not_in_dictionary', 'default'), 238 'default' 239 ) 240 241 with self.assertRaises(KeyError): 242 {}.popitem() 243 244 245# Exceptions seen 246# AssertionError 247# TypeError 248# NameError 249# KeyErrorthe test passes
close the project
I close
test_dictionaries.pyin the editorI click in the terminal and exit the tests with ctrl+c on the keyboard, the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory
Note
on Windows without Windows Subsystem for Linux
the terminal shows
(.venv) ...\pumping_python\dictionariesI deactivate the virtual environment
deactivatethe terminal goes back to the command line,
(.venv)is no longer on the left side...\pumping_python\dictionariesI change directory to the parent of
dictionariescd ..the terminal shows
...\pumping_pythonI am back in the
pumping_pythondirectory
review
Dictionaries are also known as Mappings, they contain key-value pairs and any object can be used as values.
I ran tests to show that I can make a dictionary with dict() or curly braces {}, then I ran the following tests to see what Python basic data types I can use as keys in a dictionary
I also ran these tests for the methods of dictionaries
test_items_returns_iterable_of_key_value_pairs_of_a_dictionary
test_pop_removes_given_key_from_a_dictionary_and_returns_its_value
test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary
and a test for the important Exception to know when working with dictionaries - KeyError
How many questions can you answer after going through this chapter?
code from the chapter
what is next?
you know
rate pumping python
If this has been a 7 star experience for you, please leave a 5 star review. It helps other people get into the book too