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 contains key-value pairs, the values can be any Python object. I will add tests for the keys to see which 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 in Python
requirements¶
I open a terminal to run makePythonTdd.sh with
dictionariesas the name of the project./makePythonTdd.sh dictionaries
on Windows without Windows Subsystem Linux use makePythonTdd.ps1
./makePythonTdd.ps1 dictionaries
it makes the folders and files that are needed, installs packages, runs the first test, and the terminal shows AssertionError
E AssertionError: True is not false tests/test_dictionaries.py:7: AssertionError
I hold
ctrl(windows/linux) oroption(mac) on the keyboard and use the mouse to click ontests/test_dictionaries.py:7to open it in the editorthen I change
TruetoFalseto make the test pass7self.assertFalse(False)
I change the name of the class to match the CapWords format
4class TestDictionaries(unittest.TestCase):
test_making_a_dictionary¶
red: make it fail¶
I change test_failure to test_making_a_dictionary
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
self.assertEqual(dict(), {})
the test passes. These are two ways to make an empty dictionary
refactor: make it better¶
I add another assertion, this time with input
self.assertEqual(dict(), {}) 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# Exceptions Encountered # AssertionError # TypeError
I change the value to a tuple since it is an iterable
self.assertEqual(dict(), {}) 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
self.assertEqual(dict(), {}) 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 terminal shows green again. I can make a dictionary with the dict constructor or curly braces(
{}) and I used a string as a key in this test
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
def test_making_a_dictionary(self):
...
def test_making_a_dictionary_w_none_as_a_key(self):
self.assertEqual({None: 'boom'}, {None: 'bap'})
the terminal shows AssertionError
AssertionError: {None: 'boom'} != {None: 'bap'}
green: make it pass¶
I change 'bap' to 'boom'
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
def test_making_a_dictionary_w_none_as_a_key(self):
...
def test_making_a_dictionary_w_a_boolean_as_a_key(self):
self.assertEqual({False: 'boom'}, {False: 'bap'})
the terminal shows AssertionError
AssertionError: {False: 'boom'} != {False: 'bap'}
green: make it pass¶
I change 'bap' to 'boom'
self.assertEqual({False: 'boom'}, {False: 'boom'})
the tests passes. I can use False as a key in a dictionary
refactor: make it better¶
def test_making_a_dictionary_w_a_boolean_as_a_key(self):
self.assertEqual(
{False: 'boom', True: 'bap'},
{False: 'boom'}
)
the terminal shows AssertionError
AssertionError: {False: 'boom', True: 'bap'} != {False: 'boom'}
I add the new key-value pair to the expectation
self.assertEqual(
{False: 'boom', True: 'bap'},
{False: 'boom', True: 'bap'}
)
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
def test_making_a_dictionary_w_a_boolean_as_a_key(self):
...
def test_making_a_dictionary_w_a_number_as_a_key(self):
self.assertEqual({0: 'boom'}, {0: 'bap'})
the terminal shows AssertionError
AssertionError: {0: 'boom'} != {0: 'bap'}
green: make it pass¶
I change 'bap' to 'boom'
self.assertEqual({0: 'boom'}, {0: 'boom'})
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
self.assertEqual(
{0: 'boom', 0.1: 'bap'},
{0: 'boom', 0.1: 'bap'}
)
the test passes. I can use numbers, 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 as a key in a dictionary
def test_making_a_dictionary_w_a_number_as_a_key(self):
...
def test_making_a_dictionary_w_a_tuple_as_a_key(self):
self.assertEqual(
{(0, 1): 'boom'},
{(0, 1): 'bap'}
)
the terminal shows AssertionError
AssertionError: {(0, 1): 'boom'} != {(0, 1): 'bap'}
green: make it pass¶
I change 'bap' to 'boom'
self.assertEqual(
{(0, 1): 'boom'},
{(0, 1): 'boom'}
)
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
def test_making_a_dictionary_w_a_tuple_as_a_key(self):
...
def test_making_a_dictionary_w_a_list_as_a_key(self):
self.assertEqual(
{[0, 1]: 'boom'},
)
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
def test_making_a_dictionary_w_a_list_as_a_key(self):
{[3, 2, 1]: 'BOOM!!!'}
the terminal still shows TypeError, I add assertRaises
def test_making_a_dictionary_w_a_list_as_a_key(self):
with self.assertRaises(TypeError):
{[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 try another test with a set as a key in a dictionary
def test_making_a_dictionary_w_a_list_as_a_key(self):
...
def test_making_a_dictionary_w_a_set_as_a_key(self):
{{3, 2, 1}: 'BOOM!!!'}
the terminal shows TypeError
TypeError: unhashable type: 'set'
green: make it pass¶
I add assertRaises
def test_making_a_dictionary_w_a_set_as_a_key(self):
with self.assertRaises(TypeError):
{{3, 2, 1}: 'BOOM!!!'}
the test is green again. I cannot use a 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
def test_making_a_dictionary_w_a_set_as_a_key(self):
...
def test_making_a_dictionary_w_a_dictionary_as_a_key(self):
a_dictionary = {'key': 'value'}
{a_dictionary: 'BOOM!!!'}
the terminal shows TypeError
TypeError: unhashable type: 'dict'
green: make it pass¶
I add assertRaises
def test_making_a_dictionary_w_a_dictionary_as_a_key(self):
a_dictionary = {'key': 'value'}
with self.assertRaises(TypeError):
{a_dictionary: 'BOOM!!!'}
the test passes. I cannot use a dictionaries, sets or lists as keys in a dictionary they are not hashable, which means they can change
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
def test_attributes_and_methods_of_dictionaries(self):
self.assertEqual(
dir(dict),
[]
)
the terminal shows AssertionError
AssertionError: Lists differ: ['__class__', '__class_getitem__', '__cont[530 chars]ues'] != []
It also gives me a message to show the full difference between the two lists
Diff is 720 characters long. Set self.maxDiff to None to see it.
green: make it pass¶
I move the terminal to right side of the screen, then add maxDiff to the test
def test_attributes_and_methods_of_dictionaries(self):
self.maxDiff = None
self.assertEqual(
dir(dict),
[]
)
the terminal shows the 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
def test_attributes_and_methods_of_dictionaries(self):
self.maxDiff = None
self.assertEqual(
dir(src.dictionaries.a_dict()),
[
'__class__',
...
'__subclasshook__',
'clear',
'copy',
'fromkeys',
'get',
'items',
'keys',
'pop',
'popitem',
'setdefault',
'update',
'values'
]
)
the test passes and I move the terminal back to the bottom. I copy the names that do NOT have double underscores (__) to make a TODO list of tests
'clear',
'copy',
'fromkeys',
'get',
'items',
'keys',
'pop',
'popitem',
'setdefault',
'update',
'values'
# Exceptions Encountered
# AssertionError
# TypeError
test_clear_empties_a_dictionary¶
red: make it fail¶
I add a test for the first method
def test_attributes_and_methods_of_dictionaries(self): ... def test_clear(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.clear())
I add an assertion to see what it did to the dictionary
self.assertIsNone(a_dictionary.clear()) 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
self.assertEqual(a_dictionary, {})
the test passes
refactor: make it better¶
I rename the test
def test_clear_empties_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.clear()) self.assertEqual(a_dictionary, {})
I remove clear from the TODO list
'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_copy_a_dictionary¶
red: make it fail¶
I add a test for the next method
def test_clear_empties_a_dictionary(self):
...
def test_copy(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.copy())
the terminal shows AssertionError
AssertionError: {'key': 'value'} is not None
this method returns a copy of the dictionary
green: make it pass¶
I add the value to the assertion
self.assertIsNone(a_dictionary.copy(), {'key': 'value'})
the terminal shows AssertionError
AssertionError: {'key': 'value'} is not None : {'key': 'value'}
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.copy(), {'key': 'value'})
the test passes
refactor: make it better¶
I add another assertion to see what happens to the dictionary after the call
self.assertEqual(a_dictionary.copy(), {'key': 'value'}) self.assertEqual(a_dictionary, {})
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}
it stays the same. I change the values to match
self.assertEqual(a_dictionary, {'key': 'value'})
the test is green again. This method also works the same way with lists
I rename the test
def test_copy_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.copy(), {'key': 'value'}) self.assertEqual(a_dictionary, {'key': 'value'})
I remove copy from the TODO list
'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_fromkeys_makes_a_dictionary_from_an_iterable¶
red: make it fail¶
I add a test
def test_copy_a_dictionary(self):
...
def test_fromkeys(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.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
self.assertIsNone(a_dictionary.fromkeys(0))
the terminal shows TypeError
TypeError: 'int' object is not iterable
I change the value to a tuple
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 expected values
self.assertIsNone(
a_dictionary.fromkeys((0, 1)),
{0: None, 1: None}
)
the terminal shows AssertionError
AssertionError: {0: None, 1: None} is not None : {0: None, 1: None}
I change assertIsNone to assertEqual
self.assertEqual(
a_dictionary.fromkeys((0, 1)),
{0: None, 1: None}
)
the test passes
refactor: make it better¶
I add another assert method to see what happens to the first dictionary in the test
self.assertEqual( a_dictionary.fromkeys((0, 1)), {0: None, 1: None} ) self.assertEqual(a_dictionary, {})
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}
the dictionary did not change
I remove the assertion then change the call to use the dict class
def test_fromkeys(self): a_dictionary = {'key': 'value'} self.assertEqual( dict.fromkeys((0, 1)), {0: None, 1: None} )
the test is still green. I remove
a_dictionarysince it is not useddef test_fromkeys(self): self.assertEqual( dict.fromkeys((0, 1)), {0: None, 1: None} )
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 see what will happen
self.assertEqual( dict.fromkeys((0, 1), None), {0: None, 1: None} )
the terminal still shows green. I change the second input expecting a failure
self.assertEqual( dict.fromkeys((0, 1), 'default'), {0: None, 1: None} )
the terminal shows AssertionError
AssertionError: {0: 'default', 1: 'default'} != {0: None, 1: None}
I change the values to match
self.assertEqual( dict.fromkeys((0, 1), 'default'), {0: 'default', 1: 'default'} )
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 rename the test
def test_fromkeys_makes_a_dictionary_from_an_iterable(self): self.assertEqual( dict.fromkeys((0, 1), 'default'), {0: 'default', 1: 'default'} )
I remove fromkeys from the TODO list
'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_get_value_of_a_key_in_a_dictionary¶
red: make it fail¶
I add another test
def test_fromkeys_makes_a_dictionary_from_an_iterable(self):
...
def test_get(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.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
self.assertIsNone(a_dictionary.get(0))
the terminal shows green
refactor: make it better¶
this method also expected at least 1 argument, I add None to the call
self.assertIsNone(a_dictionary.get(0, None))
the terminal still shows green. I change the second argument expecting a failure
self.assertIsNone(a_dictionary.get(0, 'default'))
the terminal shows AssertionError
AssertionError: 'default' is not None
I add the expectation
self.assertIsNone(a_dictionary.get(0, 'default'), 'default')
the terminal shows AssertionError
AssertionError: 'default' is not None : default
I change the assertion
self.assertEqual( a_dictionary.get(0, 'default'), 'default' )
the test passes. I change the
0to be more descriptiveself.assertEqual( a_dictionary.get('not_in_dictionary', 'default'), 'default' )
I want to see what would happen if I use the get method with a key that is in the dictionary
self.assertEqual( a_dictionary.get('not_in_dictionary', 'default'), 'default' ) self.assertEqual( a_dictionary.get('key', 'default'), 'default' )
the terminal shows AssertionError
AssertionError: 'value' != 'default'
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 expectation to match
self.assertEqual( a_dictionary.get('key', 'default'), 'value' )
the test passes
I change the name of the test
def test_get_value_of_a_key_in_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual( a_dictionary.get('not_in_dictionary', 'default'), 'default' ) self.assertEqual( a_dictionary.get('key', 'default'), 'default' )
the test is still green
I remove get from the TODO list
'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_items_returns_iterable_of_key_value_pairs_of_a_dictionary¶
red: make it fail¶
I add the next test from the list
def test_get_value_of_a_key_in_a_dictionary(self):
...
def test_items(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.items())
the terminal shows AssertionError
AssertionError: dict_items([('key', 'value')]) is not None
green: make it pass¶
I copy the value from the terminal and paste it as the expectation
self.assertIsNone(a_dictionary.items(), dict_items([('key', 'value')]))
the terminal shows NameError
NameError: name 'dict_items' is not defined
this new object contains a list and I know how to work with lists, I remove the stuff around it
self.assertIsNone(a_dictionary.items(), [('key', 'value')])
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 what happens
self.assertIsNone(list(a_dictionary.items()), [('key', 'value')])
the terminal shows AssertionError
AssertionError: [('key', 'value')] is not None : [('key', 'value')]
the values are the same, I change assertIsNone to assertEqual
self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the test passes. This works because the items method returns an iterable of the key-value pairs of the dictionary
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 key-value pair
def test_items(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the terminal shows AssertionError
AssertionError: Lists differ: [('key1', 'value1'), ('keyN', [0, 1, 2, 'n'])] != [('key', 'value')]
I change the expectation to match
self.assertEqual( list(a_dictionary.items()), [ ('key1', 'value1'), ('keyN', [0, 1, 2, 'n']), ] )
the test passes
I change the name of the test
def test_items_returns_iterable_of_key_value_pairs_of_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual( list(a_dictionary.items()), [ ('key1', 'value1'), ('keyN', [0, 1, 2, 'n']), ] )
I remove items from the TODO list
'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
all tests are still passing
test_keys_of_a_dictionary¶
red: make it fail¶
I add a test
def test_items_returns_iterable_of_key_value_pairs_of_a_dictionary(self):
...
def test_keys(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.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 value from the terminal and paste it as the expectation
self.assertIsNone(a_dictionary.keys(), dict_keys(['key']))
the terminal shows NameError
NameError: name 'dict_keys' is not defined
the dict_keys object contains a list, I will use it as the expectation instead
self.assertIsNone(a_dictionary.keys(), ['key'])
the terminal shows AssertionError
AssertionError: dict_keys(['key']) is not None : ['key']
I pass the call to the keys method to the list constructor
self.assertIsNone(list(a_dictionary.keys()), ['key'])
the terminal shows AssertionError
AssertionError: ['key'] is not None : ['key']
I change assertIsNone to assertEqual
self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
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
def test_keys(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual(list(a_dictionary.keys()), ['key'])
the terminal shows AssertionError
AssertionError: Lists differ: ['key1', 'keyN'] != ['key']
I change the expectation to match
self.assertEqual(list(a_dictionary.keys()), ['key1', 'keyN'])
the test passes
I change the name of the test
def test_keys_of_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual(list(a_dictionary.keys()), ['key1', 'keyN'])
I remove keys from the TODO list
'pop', 'popitem', 'setdefault', 'update', 'values'
test_pop_removes_given_key_from_a_dictionary_and_returns_its_value¶
red: make it fail¶
I wonder if the next method is the same as the one in test_pop_removes_and_returns_last_item_from_a_list, I add a test for it
def test_keys_of_a_dictionary(self):
...
def test_pop(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.pop())
the terminal shows TypeError
TypeError: pop expected at least 1 argument, got 0
green: make it pass¶
I pass a value to the call
self.assertIsNone(a_dictionary.pop(0))
the terminal shows KeyError
KeyError: 0
I add it to the list of Exceptions encountered in
test_dictionaries.py# Exceptions Encountered # AssertionError # TypeError # KeyError
I remove the things around the call and change the value given to be more descriptive
a_dictionary = {'key': 'value'} a_dictionary.pop('not in dictionary')
the terminal shows KeyError
KeyError: 'not in dictionary'
I add assertRaises
a_dictionary = {'key': 'value'} with self.assertRaises(KeyError): a_dictionary.pop('not in dictionary')
the test passes, calling the pop method with a key that is not in the dictionary raises a KeyError
refactor: make it better¶
I add another assertion
a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.pop('key')) with self.assertRaises(KeyError): a_dictionary.pop('not in dictionary')
the terminal shows AssertionError
AssertionError: 'value' is not None
the pop method returns the value of the given key from the dictionary. I add the expectation
self.assertIsNone(a_dictionary.pop('key'), 'value')
the terminal shows AssertionError
AssertionError: 'value' is not None : value
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.pop('key'), 'value')
the test passes
I add another assertion to see what the method did to the dictionary
self.assertEqual(a_dictionary.pop('key'), 'value') self.assertEqual(a_dictionary, {'key': 'value'})
the terminal shows AssertionError
AssertionError: {} != {'key': 'value'}
pop method removes the key-value pair and returns the value of the given key from the dictionary. I change the expectation to match
self.assertEqual(a_dictionary, {})
the test passes
I rename the test
def test_pop_removes_given_key_from_a_dictionary_and_returns_its_value(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.pop('key'), 'value') self.assertEqual(a_dictionary, {}) with self.assertRaises(KeyError): a_dictionary.pop('not in dictionary')
I remove pop from the TODO list
'popitem', 'setdefault', 'update', 'values'
test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary¶
red: make it fail¶
I add a failing test
def test_pop_removes_given_key_from_a_dictionary_and_returns_its_value(self):
...
def test_pop_item(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.popitem())
the terminal shows AssertionError
AssertionError: ('key', 'value') is not None
green: make it pass¶
I add the value from the terminal as an expectation
self.assertIsNone(a_dictionary.popitem(), ('key', 'value'))
the terminal shows AssertionError
AssertionError: ('key', 'value') is not None : ('key', 'value')
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.popitem(), ('key', 'value'))
the test passes
refactor: make it better¶
I want to know what the popitem method did to the dictionary
self.assertEqual(a_dictionary.popitem(), ('key', 'value')) 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
self.assertEqual(a_dictionary, {})
the test passes
this operation does not take input, I change the dictionary to see how it responds
a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], }
the terminal shows AssertionError
AssertionError: Tuples differ: ('keyN', [0, 1, 2, 'n']) != ('key', 'value')
I change the expectation to match
self.assertEqual(a_dictionary.popitem(), ('keyN', [0, 1, 2, 'n']))
the terminal shows AssertionError
AssertionError: {'key1': 'value1'} != {'key': 'value'}
I change the value to match
self.assertEqual(a_dictionary, {'key1': 'value1'})
the test passes
I add another call to the method
self.assertEqual(a_dictionary, {'key1': 'value1'}) self.assertEqual(a_dictionary.popitem(), ('keyN', [0, 1, 2, 'n']))
the terminal shows AssertionError
AssertionError: Tuples differ: ('key1', 'value1') != ('keyN', [0, 1, 2, 'n'])
I change the expectation
self.assertEqual(a_dictionary.popitem(), ('key1', 'value1'))
the test passes. popitem removes and returns the last key-value pair from a dictionary
I change the name of the test
def test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual(a_dictionary.popitem(), ('keyN', [0, 1, 2, 'n'])) self.assertEqual(a_dictionary, {'key1': 'value1'}) self.assertEqual(a_dictionary.popitem(), ('key1', 'value1'))
I remove popitem from the TODO list
'setdefault', 'update', 'values'
test_setdefault_adds_given_key_to_a_dictionary¶
red: make it fail¶
I add a test
def test_setdefault(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.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
self.assertIsNone(a_dictionary.setdefault(0))
the test passes
refactor: make it better¶
I add an assertion to see what it did to the dictionary
self.assertIsNone(a_dictionary.setdefault(0)) self.assertEqual(a_dictionary, {'key': 'value'})
the terminal shows AssertionError
AssertionError: {'key': 'value', 0: None} != {'key': 'value'}
setdefault adds the given key to the dictionary with a default value of None and returns the default value
I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'value', 0: None, } )
the test passes
I change the name of the value given
a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.setdefault('new_key')) self.assertEqual( a_dictionary, { 'key': 'value', 0: None, } )
the terminal shows AssertionError
AssertionError: {'key': 'value', 'new_key': None} != {'key': 'value', 0: None}
I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'value', 'new_key': None, } )
the test is green again
I add an assertion to see what happens when the key is already in the dictionary
self.assertIsNone(a_dictionary.setdefault('new_key')) self.assertIsNone(a_dictionary.setdefault('key'))
the terminal shows AssertionError
AssertionError: 'value' is not None
setdefault returns the value for a key in a dictionary when the key is in the dictionary. I add the value to the assertion
self.assertIsNone(a_dictionary.setdefault('key'), 'value')
the terminal shows AssertionError
AssertionError: 'value' is not None : value
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.setdefault('key'), 'value')
the test passes
It looks like setdefault has a condition where it sets a default value when the key is not in the dictionary and returns the value when the key is in it. I change the first assertion to find out
self.assertIsNone(a_dictionary.setdefault('new_key', None))
the terminal still shows green. I change the given default value expecting a failure
self.assertIsNone(a_dictionary.setdefault('new_key', 'default'))
the terminal shows AssertionError
AssertionError: 'default' is not None
I add the expected value
self.assertIsNone(a_dictionary.setdefault('new_key', 'default'), 'default')
the terminal shows AssertionError
AssertionError: 'default' is not None : default
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.setdefault('new_key', 'default'), 'default')
the terminal shows AssertionError
AssertionError: {'key': 'value', 'new_key': 'default'} != {'key': 'value', 'new_key': None}
I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'value', 'new_key': 'default', } )
the test passes
I try the same thing with the second assertion
self.assertEqual(a_dictionary.setdefault('key', 'default'), 'value')
the terminal still shows green. setdefault adds a given key to the dictionary with a given default value and returns the default value if the key is not in the dictionary. It returns the value for a key that is already in the dictionary
I rename the test
def test_setdefault_adds_given_key_to_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.setdefault('new_key', 'default'), 'default') self.assertEqual(a_dictionary.setdefault('key', 'default'), 'value') self.assertEqual( a_dictionary, { 'key': 'value', 'new_key': 'default', } )
I remove setdefault from the TODO list
'update', 'values'
test_update_a_dictionary¶
red: make it fail¶
I add a test for the next method
def test_setdefault_adds_given_key_to_a_dictionary(self): ... def test_update(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.update())
I add an assertion to see what it did to the dictionary
self.assertIsNone(a_dictionary.update()) self.assertEqual(a_dictionary, {})
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}
the dictionary stayed the same
green: make it pass¶
I change the values in the expectation to match the terminal
self.assertEqual(a_dictionary, {'key': 'value'})
the test passes
refactor: make it better¶
I add a value to the call to see what would happen
self.assertIsNone(a_dictionary.update(0))
the terminal shows TypeError
TypeError: 'int' object is not iterable
I change the value to a tuple
self.assertIsNone(a_dictionary.update((0, 1)))
the terminal shows TypeError
TypeError: cannot convert dictionary update sequence element #0 to a sequence
I had this same error message in test_making_a_dictionary. I try a keyword argument
self.assertIsNone(a_dictionary.update(new_key='new value'))
the terminal shows AssertionError
AssertionError: {'key': 'value', 'new_key': 'new value'} != {'key': 'value'}
I add the new key-value pair to the assertion
self.assertEqual( a_dictionary, { 'key': 'value', 'new_key': 'new value' } )
the test passes
I add an assertion to see what would happen if I give a key that is already in the dictionary
self.assertIsNone(a_dictionary.update(new_key='new value')) self.assertIsNone(a_dictionary.update(key='updated value'))
the terminal shows AssertionError
AssertionError: {'key': 'updated value', 'new_key': 'new value'} != {'key': 'value', 'new_key': 'new value'}
the update method changes the value for a key that is already in a dictionary. I change the expectation to match. I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'updated value', 'new_key': 'new value' } )
the test passes
since the update method takes keyword arguments it means I should be able to give it a dictionary as input. I add another assertion
self.assertIsNone(a_dictionary.update({'another_key': 'another_value'}))
the terminal shows AssertionError
AssertionError: {'key': 'updated value', 'new_key': 'new value', 'another_key': 'another_value'} != {'key': 'updated value', 'new_key': 'new value'}
the update method adds the key-value pairs from the given dictionary to the existing one. I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'updated value', 'new_key': 'new value', 'another_key': 'another_value', } )
the test passes
I rename the test
def test_update_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.update(new_key='new value')) self.assertIsNone(a_dictionary.update(key='updated value')) self.assertIsNone(a_dictionary.update({'another_key': 'another_value'})) self.assertEqual( a_dictionary, { 'key': 'updated value', 'new_key': 'new value', 'another_key': 'another_value', } )
the test is still green
I remove update from the TODO list
'values'
test_values_of_a_dictionary¶
red: make it fail¶
I add a test for the last method
def test_update_a_dictionary(self):
...
def test_values(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.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
self.assertIsNone(a_dictionary.values, dict_values(['value']))
the terminal shows NameError
NameError: name 'dict_values' is not defined
I use the list in the dict_values object
self.assertIsNone(a_dictionary.values(), ['value'])
the terminal shows AssertionError
AssertionError: dict_values(['value']) is not None : ['value']
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.values(), ['value'])
the terminal shows AssertionError
AssertionError: dict_values(['value']) != ['value']
I pass the call to the list constructor
self.assertEqual(list(a_dictionary.values()), ['value'])
the test passes
refactor: make it better¶
I change the dictionary
a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], }
the terminal shows AssertionError
AssertionError: Lists differ: ['value1', [0, 1, 2, 'n']] != ['value']
I change the values in the expectation
self.assertEqual( list(a_dictionary.values()), ['value1', [0, 1, 2, 'n']] )
the test passes
I rename the test
def test_values_of_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': [0, 1, 2, 'n'], } self.assertEqual( list(a_dictionary.values()), ['value1', [0, 1, 2, 'n']] )
I remove values from the TODO list
test_key_error¶
The KeyError is an important Exception to know when working with a dictionary
red: make it fail¶
I add a test for getting the value of a key that is in a dictionary
def test_values_of_a_dictionary(self):
...
def test_key_error(self):
a_dictionary = {'key': 'value'}
self.assertEqual(a_dictionary['key'], '')
the terminal shows AssertionError
AssertionError: 'value' != ''
I can get the value for a key in a dictionary by giving it in [], this is like viewing items in a list
green: make it pass¶
I change the value in the expectation to match the terminal
self.assertEqual(a_dictionary['key'], 'value')
the test passes
refactor: make it better¶
I add another assertion
self.assertEqual(a_dictionary['key'], 'value') self.assertEqual(a_dictionary['not_in_dictionary'])
the terminal shows KeyError
KeyError: 'key_not_in_dictionary'
I change the assertEqual to assertRaises
self.assertEqual(a_dictionary['key'], 'value') with self.assertRaises(KeyError): a_dictionary['not_in_dictionary']
the test passes
I add an assertion to show that I can use the get method if I do not want to get KeyError with a key that is not in a dictionary
self.assertEqual(a_dictionary['key'], 'value') self.assertEqual(a_dictionary.get('not_in_dictionary', 'default'), 'value')
the terminal shows AssertionError
AssertionError: 'default' != 'value'
I change the expectation
self.assertEqual(a_dictionary.get('not_in_dictionary', 'default'), 'default')
the test passes
Earlier on in test_pop_removes_given_key_from_a_dictionary_and_returns_its_value the pop method raised KeyError with a key that was not in the dictionary, I add an assertion for it
with self.assertRaises(KeyError): a_dictionary['not_in_dictionary'] a_dictionary.pop('not_in_dictionary')
the terminal shows KeyError
KeyError: 'not_in_dictionary'
I add assertRaises
with self.assertRaises(KeyError): a_dictionary['not_in_dictionary'] with self.assertRaises(KeyError): a_dictionary.pop('not_in_dictionary')
the test passes
The popitem method also raises KeyError when called on an empty dictionary
with self.assertRaises(KeyError): a_dictionary.pop('not_in_dictionary') {}.popitem()
the terminal shows KeyError
KeyError: 'popitem(): dictionary is empty'
I add assertRaises
with self.assertRaises(KeyError): a_dictionary.pop('not_in_dictionary') with self.assertRaises(KeyError): {}.popitem()
review¶
I ran tests for dictionaries
they contain key-value pairs
any object can be used as values
strings, booleans, integers, floats and tuples can be used as keys
they can be represented with
{}they can be made with the dict constructor
Would you like to test functions?