Danger

DANGER WILL ROBINSON! Though the code works, this chapter is still UNDER CONSTRUCTION it may look completely different when I am done

dictionaries


A dictionary also known as a Mapping is a way to keep key-value pairs, the values can be any Python object. I add tests for the keys to see which of the Python basic data types I can use.

I think this is the most important data structure to know because they can hold all the other data structures. In programming I have had to work with JSON which I can read and write as 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({'another_key': {0, 1, 2, 'n'}}))
199        self.assertEqual(
200            a_dictionary,
201            {
202                'key': 'updated value',
203                'new_key': [0, 1, 2, 'n'],
204                'another_key': {0, 1, 2, 'n'},
205            }
206        )
207
208    def test_values_of_a_dictionary(self):
209        a_dictionary = {
210            'key1': 'value1',
211            'keyN': [0, 1, 2, 'n'],
212        }
213        self.assertEqual(
214            list(a_dictionary.values()),
215            [
216                'value1',
217                [0, 1, 2, 'n'],
218            ]
219        )
220
221    def test_key_error(self):
222        a_dictionary = {'key': 'value'}
223        self.assertEqual(a_dictionary['key'], 'value')
224
225        with self.assertRaises(KeyError):
226            a_dictionary['not_in_dictionary']
227        self.assertEqual(
228            a_dictionary.get('not_in_dictionary', 'default'),
229            'default'
230        )
231
232        with self.assertRaises(KeyError):
233            a_dictionary.pop('not_in_dictionary')
234        self.assertEqual(
235            a_dictionary.pop('not_in_dictionary', 'default'),
236            'default'
237        )
238
239        with self.assertRaises(KeyError):
240            {}.popitem()
241
242
243# Exceptions Encountered
244# AssertionError
245# TypeError
246# KeyError

requirements


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 one

  • with the constructor - dict() and with

  • curly braces - {}

REFACTOR: make it better

  • I add another assertion, this time with input

    6    def test_making_a_dictionary(self):
    7        self.assertEqual(dict(), {})
    8        self.assertEqual(dict(0), {})
    

    the terminal shows TypeError

    TypeError: 'int' object is not iterable
    
  • I add the error to the list of Exceptions encountered in test_dictionaries.py

    11# Exceptions Encountered
    12# AssertionError
    13# TypeError
    
  • I change the value to a tuple since it is an iterable

    7        self.assertEqual(dict(), {})
    8        self.assertEqual(dict((0, 1)), {})
    

    the terminal shows TypeError

    TypeError: cannot convert dictionary update sequence element #0 to a sequence
    
  • I 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

    self.assertEqual(dict(key='value'), {'key': 'value'})
    

    the test passes.

I can make a dictionary with the dict constructor or curly braces({}) and I used a string as a key in this test. Next I test the 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 Encountered

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 None and strings 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 Encountered

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 booleans, None and strings 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 Encountered

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

def test_making_a_dictionary_w_a_number_as_a_key(self):
    self.assertEqual(
        {0: 'boom', 0.1: 'bap'},
        {0: 'boom'}
    )

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 numbers (floats and integers), booleans, None and strings 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 (())) as a key in a dictionary

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 Encountered

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, numbers (floats and integers), booleans, None and strings 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 ([]))

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 Encountered

the terminal shows TypeError

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!!!'}

the terminal still shows TypeError. 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 a curly braces ({})) as a key in a dictionary

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 Encountered

the terminal shows TypeError

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

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 Encountered

the terminal shows TypeError

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 Encountered

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 function to see the attributes and methods of dictionaries

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 Encountered

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.

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 move the terminal to right side of the screen

  • 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 and paste 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 Encountered
    

    the terminal still shows green

  • I move the terminal back to the bottom of the screen


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',
    104'copy',
    

    the terminal shows 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',
    105'copy',
    
  • I remove clear from the TODO list

    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 next 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

    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

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',

the terminal shows TypeError

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))
    

    the terminal shows TypeError

    TypeError: 'int' object is not iterable
    
  • I 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 None
    

    the fromkeys method returns a dictionary that uses the values in the iterable as keys with default values of None

  • 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 happens to the first dictionary in the test

    110    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

  • I change the call fromkeys to use the dict class instead

    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_dictionary since it is not used

    110    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 0
    

    I 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 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

    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

107            {0: 'default', 1: 'default'}
108        )
109
110    def test_get(self):
111        a_dictionary = {'key': 'value'}
112        self.assertIsNone(a_dictionary.get())
113
114
115'get',

the terminal shows TypeError

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 None
    
  • I add the expectation

    118    def test_get(self):
    119        a_dictionary = {'key': 'value'}
    120        self.assertIsNone(
    121            a_dictionary.get(0, 'default'),
    122            'default'
    123        )
    

    the terminal shows AssertionError

    AssertionError: 'default' is not None : default
    
  • I change assertIsNone to assertEqual

    118        self.assertEqual(
    119            a_dictionary.get(0, 'default'),
    120            'default'
    121        )
    

    the test passes

  • I change 0 in the call to get to be more descriptive

    118        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' back. I change the expectation to match

    122        self.assertEqual(
    123            a_dictionary.get('key', 'default'),
    124            'value'
    125        )
    

    the test passes.

    The get method has a condition

  • 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

    128'items',
    129'keys',
    130'pop',
    131'popitem',
    132'setdefault',
    133'update',
    134'values'
    

test_items_returns_iterable_of_key_value_pairs_of_a_dictionary

RED: make it fail

I add the next test from the TODO list

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_items object from the terminal and paste it as the expectation

    129        self.assertIsNone(
    130            a_dictionary.items(),
    131            dict_items([('key', 'value')])
    132        )
    

    the terminal shows NameError

    NameError: name 'dict_items' is not defined
    

    this new object has a list and I know how to work with lists

  • I 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 the list constructor to see if it is iterable

    129        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

    141'keys',
    142'pop',
    143'popitem',
    144'setdefault',
    145'update',
    146'values'
    

    all tests are still passing


test_keys_of_a_dictionary

RED: make it fail

I add a new test

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_keys object from the terminal and paste it as the expectation

    140    def test_keys(self):
    141        a_dictionary = {'key': 'value'}
    142        self.assertIsNone(
    143            a_dictionary.keys(),
    144            dict_keys(['key'])
    145        )
    

    the terminal shows NameError

    NameError: name 'dict_keys' is not defined
    

    the dict_keys object contains a list

  • I use the list in the dict_keys object as the expectation instead

    142    def test_keys(self):
    143        a_dictionary = {'key': 'value'}
    144        self.assertIsNone(
    145            a_dictionary.keys(),
    146            ['key']
    147        )
    

    the terminal shows AssertionError

    AssertionError: dict_keys(['key']) is not None : ['key']
    
  • I pass the call to the keys method to the list constructor to see if dict_keys is iterable

    142        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

    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 next method behaves the same way as it did in test_pop_removes_and_returns_last_item_from_a_list, I add a test for it

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',

the terminal shows TypeError

TypeError: pop expected at least 1 argument, got 0

this pop method is different from the one in lists

GREEN: make it pass

  • I pass a value to the call

    152        self.assertIsNone(a_dictionary.pop(0))
    

    the terminal shows KeyError

    KeyError: 0
    
  • I add it to the list of Exceptions encountered

    162# Exceptions Encountered
    163# AssertionError
    164# TypeError
    165# KeyError
    
  • I remove the things around the call in the test and change the value given to be more descriptive

    150    def test_pop(self):
    151        a_dictionary = {'key': 'value'}
    152        a_dictionary.pop('not_in_dictionary')
    

    the terminal shows KeyError

    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 0
    

    I 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 None
    

    I 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 : default
    
  • I 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 dictionary

  • I 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

    163self.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

    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 want to know what the popitem method did to the dictionary. I add another assertion

    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')
    

    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

    self.assertEqual(a_dictionary, {'key1': 'value1'})
    

    the test passes. popitem removes and returns the last key-value pair from a dictionary

  • 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

    177'setdefault',
    178'update',
    179'values'
    

test_setdefault_adds_given_key_to_a_dictionary

RED: make it fail

I add a test for the next 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',

the terminal shows TypeError

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 None
    
  • I 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 : default
    
  • I 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: None,
    187            }
    188        )
    

    the test passes

  • I change the 0 given to the call to be more descriptive

    178        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

    182        self.assertEqual(
    183            a_dictionary,
    184            {
    185                'key': 'value',
    186                'new_key': 'default',
    187            }
    188        )
    

    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

    178    def test_setdefault(self):
    179        a_dictionary = {'key': 'value'}
    180        self.assertEqual(
    181            a_dictionary.setdefault('new_key', 'default'),
    182            'default'
    183        )
    184        self.assertEqual(
    185            a_dictionary.setdefault('key', 'default'),
    186            'default'
    187        )
    188        self.assertEqual(
    189            a_dictionary,
    190            {
    191                'key': 'value',
    192                'new_key': 'default',
    193            }
    194        )
    

    the terminal shows AssertionError

    AssertionError: 'value' != 'default'
    

    I get 'value' back. 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

  • setdefault has a condition

  • 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

    195'update',
    196'values'
    

test_update_a_dictionary

RED: make it fail

  • I add a test for the next method from the TODO list

    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'})
    

    the terminal shows TypeError

    TypeError: 'int' object is not iterable
    

    I change the value to a tuple

    196        self.assertIsNone(a_dictionary.update((0, 1)))
    

    the terminal shows TypeError

    TypeError: cannot convert dictionary update sequence element #0 to a sequence
    

    I 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({'another_key': {0, 1, 2, 'n'}}))
    199        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 to match

    199        self.assertEqual(
    200            a_dictionary,
    201            {
    202                'key': 'updated value',
    203                'new_key': [0, 1, 2, 'n'],
    204                'another_key': {0, 1, 2, 'n'},
    205            }
    206        )
    

    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({'another_key': {0, 1, 2, 'n'}}))
    199        self.assertEqual(
    200            a_dictionary,
    201            {
    202                'key': 'updated value',
    203                'new_key': [0, 1, 2, 'n'],
    204                'another_key': {0, 1, 2, 'n'},
    205            }
    206        )
    207
    208
    209'update',
    

    the test is still green

  • I remove update from the TODO list

    209'values'
    

test_values_of_a_dictionary

RED: make it fail

I add a test for the last method

204                'another_key': {0, 1, 2, 'n'},
205            }
206        )
207
208    def test_values(self):
209        a_dictionary = {'key': 'value'}
210        self.assertIsNone(a_dictionary.values())
211
212
213'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

    208    def test_values(self):
    209        a_dictionary = {'key': 'value'}
    210        self.assertIsNone(
    211            a_dictionary.values,
    212            dict_values(['value'])
    213        )
    

    the terminal shows NameError

    NameError: name 'dict_values' is not defined
    
  • I remove the things around the list in the dict_values object

    210        self.assertIsNone(
    211            a_dictionary.values(),
    212            ['value']
    213        )
    

    the terminal shows AssertionError

  • I use the list constructor to see if dict_values is iterable

    210        self.assertIsNone(
    211            list(a_dictionary.values()),
    212            ['value']
    213        )
    

    the terminal shows AssertionError

    AssertionError: ['value'] is not None : ['value']
    
  • I change assertIsNone to assertEqual

    210        self.assertEqual(
    211            list(a_dictionary.values()),
    212            ['value']
    213        )
    

    the test passes

REFACTOR: make it better

  • I change the dictionary to see what happens when it has more than one key-value pair

    208    def test_values(self):
    209        a_dictionary = {
    210            'key1': 'value1',
    211            'keyN': [0, 1, 2, 'n'],
    212        }
    213        self.assertEqual(
    214            list(a_dictionary.values()),
    215            ['value']
    216        )
    

    the terminal shows AssertionError

    AssertionError: Lists differ: ['value1', [0, 1, 2, 'n']] != ['value']
    
  • I change the values in the expectation

    213        self.assertEqual(
    214            list(a_dictionary.values()),
    215            [
    216                'value1',
    217                [0, 1, 2, 'n'],
    218            ]
    219        )
    

    the test passes

  • I change the name of the test

    208    def test_values_of_a_dictionary(self):
    209        a_dictionary = {
    210            'key1': 'value1',
    211            'keyN': [0, 1, 2, 'n'],
    212        }
    213        self.assertEqual(
    214            list(a_dictionary.values()),
    215            [
    216                'value1',
    217                [0, 1, 2, 'n'],
    218            ]
    219        )
    220
    221
    222'values'
    
  • I remove values from the TODO list


test_key_error

The KeyError is an important Exception to know when working with a dictionary. It happened earlier in test_pop_removes_given_key_from_a_dictionary_and_returns_its_value

RED: make it fail

I add a test for getting the value of a key that is in a dictionary

217                [0, 1, 2, 'n'],
218            ]
219        )
220
221    def test_key_error(self):
222        a_dictionary = {'key': 'value'}
223        self.assertEqual(a_dictionary['key'], '')
224
225
226# Exceptions Encountered

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 [], just like viewing items in a list by giving the index

GREEN: make it pass

I change the value in the expectation to match the terminal

223        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

    224        self.assertEqual(a_dictionary['key'], 'value')
    225        self.assertEqual(a_dictionary['not_in_dictionary'])
    

    the terminal shows KeyError

    KeyError: 'not_in_dictionary'
    

    I change the assertEqual to assertRaises

    223        self.assertEqual(a_dictionary['key'], 'value')
    224
    225        with self.assertRaises(KeyError):
    226            a_dictionary['not_in_dictionary']
    

    the test passes

  • I can use the get method if I do not want to get KeyError with a key that is not in a dictionary

    225        with self.assertRaises(KeyError):
    226            a_dictionary['not_in_dictionary']
    227        self.assertEqual(
    228            a_dictionary.get('not_in_dictionary', 'default'),
    229            ''
    230        )
    

    the terminal shows AssertionError

    AssertionError: 'default' != ''
    

    I change the expectation

    227        self.assertEqual(
    228            a_dictionary.get('not_in_dictionary', 'default'),
    229            'default'
    230        )
    

    the test passes. This is a repetition of test_get_value_of_a_key_in_a_dictionary, here is another repetition

  • Earlier on in test_pop_removes_given_key_from_a_dictionary_and_returns_its_value the pop method raised KeyError when I gave it a key that was not in the dictionary, I add another assertion for it

    227        self.assertEqual(
    228            a_dictionary.get('not_in_dictionary', 'default'),
    229            'default'
    230        )
    231        a_dictionary.pop('not_in_dictionary')
    

    the terminal shows KeyError

    KeyError: 'not_in_dictionary'
    

    I add assertRaises

    227        self.assertEqual(
    228            a_dictionary.get('not_in_dictionary', 'default'),
    229            'default'
    230        )
    231
    232        with self.assertRaises(KeyError):
    233            a_dictionary.pop('not_in_dictionary')
    

    the test passes

  • I can give a second argument if I do not want the pop method to raise KeyError when the key is not in the dictionary. I add an assertion

    232        with self.assertRaises(KeyError):
    233            a_dictionary.pop('not_in_dictionary')
    234        self.assertEqual(
    235            a_dictionary.pop('not_in_dictionary', 'default'),
    236            ''
    237        )
    

    the terminal shows AssertionError

    AssertionError: 'default' != ''
    

    I change the expectation to match

    234        self.assertEqual(
    235            a_dictionary.pop('not_in_dictionary', 'default'),
    236            'default'
    237        )
    

    the test passes

  • The popitem method also raises KeyError when called on an empty dictionary

    234        self.assertEqual(
    235            a_dictionary.pop('not_in_dictionary', 'default'),
    236            'default'
    237        )
    238        {}.popitem()
    

    the terminal shows KeyError

    KeyError: 'popitem(): dictionary is empty'
    

    I add assertRaises

    221    def test_key_error(self):
    222        a_dictionary = {'key': 'value'}
    223        self.assertEqual(a_dictionary['key'], 'value')
    224
    225        with self.assertRaises(KeyError):
    226            a_dictionary['not_in_dictionary']
    227        self.assertEqual(
    228            a_dictionary.get('not_in_dictionary', 'default'),
    229            'default'
    230        )
    231
    232        with self.assertRaises(KeyError):
    233            a_dictionary.pop('not_in_dictionary')
    234        self.assertEqual(
    235            a_dictionary.pop('not_in_dictionary', 'default'),
    236            'default'
    237        )
    238
    239        with self.assertRaises(KeyError):
    240            {}.popitem()
    241
    242
    243# Exceptions Encountered
    244# AssertionError
    245# TypeError
    246# KeyError
    

    the test passes


review

I ran tests for dictionaries

Would you like to test How to make a Person?


Click Here for the code from this chapter


you know

Would you like to put it all together in Classes?