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 but not the keys. I think this is the most important data structure to know as it can hold all the other data structures. In programming I have to deal with JSON which I can read and write as dictionaries in Python
requirements¶
I open a terminal to run makePythonTdd.sh with
dictionaries
as 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:7
to open it in the editorthen change
True
toFalse
to make the test pass
test_making_a_dictionary¶
red: make it fail¶
I change test_failure
class TestDictionaries(unittest.TestCase):
def test_making_a_dictionary(self):
self.assertEqual(dict(), None)
the terminal shows AssertionError
AssertionError: {} != None
green: make it pass¶
I copy the value from the terminal and paste it to replace None
self.assertEqual(dict(), {})
this is how to make an empty dictionary. I can make a dictionary with the dict constructor or curly braces({}
)
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
# Exceptions Encountered # AssertionError # TypeError
I change the value to 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 instead
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. This test uses strings as keys
test_making_a_dictionary_w_none_as_a_key¶
red: make it fail¶
I add a test where I use None as a key in a dictionary
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 as a key in a dictionary
test_making_a_dictionary_w_a_boolean_as_a_key¶
red: make it fail¶
I add a test where I 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¶
I add True as a key
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 a boolean as a key in a dictionary
test_making_a_dictionary_w_a_number_as_a_key¶
red: make it fail¶
I add a failing test
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 add a float as a key
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 integers and floats as keys in a dictionary
test_making_a_dictionary_w_a_tuple_as_a_key¶
red: make it fail¶
I add a test for a tuple as a key
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 a tuple as a key in a dictionary
test_making_a_dictionary_w_a_list_as_a_key¶
red: make it fail¶
I add another test
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'
only hashable objects can be used as keys in a dictionary
green: make it pass¶
I remove the things around the new dictionary then change the key for fun
def test_making_a_dictionary_w_a_list_as_a_key(self):
{[3, 2, 1]: 'BOOM!'}
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 make a dictionary with a list as a key
test_making_a_dictionary_w_a_set_as_a_key¶
red: make it fail¶
I try the same thing with a set as a key
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 set as a key in a dictionary
test_making_a_dictionary_w_a_dictionary_as_a_key¶
red: make it fail¶
I add a new 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 dictionary, set or list as a key in a dictionary they are not hashable
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 view the entire 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 so I can see the entire difference, then add maxDiff
def test_attributes_and_methods_of_dictionaries(self):
self.maxDiff = None
self.assertEqual(
dir(dict),
[
]
)
the terminal shows the entire difference between the two lists. I copy and paste the expected values from the terminal and use find and replace to remove the extra characters
Note
results can be different because of 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 for the next set 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 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
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
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 passed 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 an assert method to see what happens to the first dictionary in the test
self.assertEqual( a_dictionary.fromkeys((0, 1, 2, 3)), {0: None, 1: None, 2: None, 3: 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_dictionary
since it is not useddef test_fromkeys(self): self.assertEqual( dict.fromkeys((0, 1)), {0: None, 1: None} )
the dictionary the fromkeys method returns has None as a default value, I write it explicitly in the test
self.assertEqual( dict.fromkeys((0, 1), None), {0: None, 1: None} )
the terminal still shows green. I change it to see if I get 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
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_a_value_from_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¶
I add another assertion, this time with something from the dictionary
self.assertIsNone(a_dictionary.get(0)) self.assertIsNone(a_dictionary.get('key'))
the terminal shows AssertionError
AssertionError: 'value' is not None
it looks like the get method has a condition where it returns the value for the key it is given from the dictionary if it is there or returns None if the key is not there. I add the expected value
self.assertIsNone(a_dictionary.get('key'), 'value')
the terminal shows AssertionError
AssertionError: 'value' is not None : value
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.get('key'), 'value')
the test passes
I change the key in the first assertion for fun
def test_get(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.get('not_in_dictionary')) self.assertEqual(a_dictionary.get('key'), 'value')
the test is still green. I add a parameter to see if I can set a default value
self.assertIsNone(a_dictionary.get('not_in_dictionary', None))
the test is still passing. I change the value to see if I get an error
self.assertIsNone(a_dictionary.get('not_in_dictionary', 'default'))
the terminal shows AssertionError
AssertionError: 'default' is not None
I add the expectation
self.assertIsNone(a_dictionary.get('not_in_dictionary', 'default'), 'default')
the terminal shows AssertionError
AssertionError: 'default' is not None : default
I change assertIsNone to assertEqual
self.assertEqual(a_dictionary.get('not_in_dictionary', 'default'), 'default')
the test is green again
I do the same thing with the second assertion
self.assertEqual(a_dictionary.get('key', 'default'), 'value')
the test is still green. The get method returns the value for a given key in a dictionary or returns a default value if the key is not there
I change the name of the test
def test_get_a_value_from_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.get('not_in_dictionary', 'default'), 'default') self.assertEqual(a_dictionary.get('key', 'default'), 'value')
the test is still green
I remove get from the TODO list
'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_items_returns_key_value_pairs_of_a_dictionary¶
red: make it fail¶
I add a test
def test_get_a_value_from_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 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, I will use it as the expectation instead
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
self.assertIsNone(list(a_dictionary.items()), [('key', 'value')])
the terminal shows AssertionError
AssertionError: [('key', 'value')] is not None : [('key', 'value')]
I change assertIsNone to assertEqual
self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the test passes. It looks like the items method returns the key-value pairs of a dictionary as tuples in a list
refactor: make it better¶
I add another key-value pair to the dictionary
def test_items(self): a_dictionary = { 'key1': 'value1', 'keyN': 'valueN', } self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the terminal shows AssertionError
AssertionError: Lists differ: [('key1', 'value1'), ('keyN', 'valueN')] != [('key', 'value')]
I change the expectation to match
self.assertEqual( list(a_dictionary.items()), [('key1', 'value1'), ('keyN', 'valueN')] )
the test passes
I change the name of the test
def test_items_returns_key_value_pairs_of_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': 'valueN', } self.assertEqual( list(a_dictionary.items()), [('key1', 'value1'), ('keyN', 'valueN')] )
I remove items from the TODO list
'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_keys_of_a_dictionary¶
red: make it fail¶
I add a test
def test_items_returns_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_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': 'valueN', } 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': 'valueN', } 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¶
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
# 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(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(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': 'valueN', }
the terminal shows AssertionError
AssertionError: Tuples differ: ('keyN', 'valueN') != ('key', 'value')
I change the expectation to match
self.assertEqual(a_dictionary.popitem(), ('keyN', 'valueN'))
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', 'valueN'))
the terminal shows AssertionError
AssertionError: Tuples differ: ('key1', 'value1') != ('keyN', 'valueN')
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': 'valueN', } self.assertEqual(a_dictionary.popitem(), ('keyN', 'valueN')) 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_key_w_a_default_value_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_key_w_a_default_value_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_key_w_a_default_value_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_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': 'valueN', }
the terminal shows AssertionError
AssertionError: Lists differ: ['value1', 'valueN'] != ['value']
I change the values in the expectation
self.assertEqual( list(a_dictionary.values()), ['value1', 'valueN'] )
the test passes
I rename the test
def test_values_of_a_dictionary(self): a_dictionary = { 'key1': 'value1', 'keyN': 'valueN', } self.assertEqual( list(a_dictionary.values()), ['value1', 'valueN'] )
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 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?