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 and in your programming journey you will come across JSON which you 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_make_a_dictionary_w_dict_constructor¶
red: make it fail¶
I change test_failure
class TestDictionaries(unittest.TestCase):
def test_make_a_dictionary_w_dict_constructor(self):
self.assertEqual(dict(key='value'), None)
the terminal shows AssertionError
AssertionError: {'key': 'value'} != None
green: make it pass¶
I copy the value from the terminal and paste it to replace None
self.assertEqual(dict(key='value'), {'key': 'value'})
the test passes
test_make_a_dictionary_w_curly_braces¶
I can make a dictionary with the dict constructor and the passing test shows I can make one with {}
.
red: make it fail¶
I add a test
def test_make_a_dictionary_w_dict_constructor(self):
...
def test_make_a_dictionary_w_curly_braces(self):
self.assertEqual({'key': 'value'}, dict(key='key'))
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {'key': 'key'}
green: make it pass¶
I make the values match
self.assertEqual({'key': 'value'}, dict(key='value'))
the test
test_make_a_dictionary_w_booleans_as_keys¶
I wonder if it is possible to use False or True as dictionary keys
red: make it fail¶
I add a test
def test_make_a_dictionary_w_curly_braces(self):
...
def test_make_a_dictionary_w_booleans_as_keys(self):
self.assertEqual({False: 'boom'}, {'False': 'boom'})
the terminal shows AssertionError
AssertionError: {False: 'boom'} != {'False': 'boom'}
green: make it pass¶
I match the keys
self.assertEqual({False: 'boom'}, {False: 'boom'})
I can use False as a key in a dictionary
refactor: make it better¶
I add another assertion
self.assertEqual({False: 'boom'}, {False: 'boom'})
self.assertEqual({True: 'bap'}, {'True': 'bap'})
the terminal shows AssertionError
AssertionError: {True: 'bap'} != {'True': 'bap'}
I change the expectation
self.assertEqual({True: 'bap'}, {True: 'bap'})
the test passes. I can use a boolean as a key in a dictionary
test_make_a_dictionary_w_numbers_as_keys¶
red: make it fail¶
I add a failing test
def test_make_a_dictionary_w_booleans_as_keys(self):
...
def test_make_a_dictionary_w_numbers_as_keys(self):
self.assertEqual({0: 'boom'}, {'zero': 'boom'})
the terminal shows AssertionError
AssertionError: {0: 'boom'} != {'zero': 'boom'}
green: make it pass¶
I change the key in the exception
def test_make_a_dictionary_w_numbers_as_keys(self):
self.assertEqual({0: 'boom'}, {0: 'boom'})
the test passes. I can use integers keys in a dictionary
refactor: make it better¶
I add an assertion for floats
self.assertEqual({0: 'boom'}, {0: 'boom'})
self.assertEqual({0.1: 'bap'}, {'0.1': 'bap'})
the terminal shows AssertionError
AssertionError: {0.1: 'bap'} != {'0.1': 'bap'}
I make the keys match
self.assertEqual({0.1: 'bap'}, {0.1: 'bap'})
the test passes. I can use integers and floats as keys in a dictionary
test_make_a_dictionary_w_tuples_as_keys¶
red: make it fail¶
I add a test for tuples
def test_make_a_dictionary_w_booleans_as_keys(self):
...
def test_make_a_dictionary_w_tuples_as_keys(self):
self.assertEqual(
{(0, 1): 'value'},
{(0, 1): 'key'}
)
the terminal shows AssertionError
AssertionError: {(0, 1): 'value'} != {(0, 1): 'key'}
green: make it pass¶
I make the values match
self.assertEqual(
{(0, 1): 'value'},
{(0, 1): 'value'}
)
the test passes
test_make_a_dictionary_w_lists_as_keys¶
red: make it fail¶
I add another test
def test_make_a_dictionary_w_tuples_as_keys(self):
...
def test_make_a_dictionary_w_lists_as_keys(self):
self.assertEqual(
{[3, 2, 1]: 'BOOM!'},
{[3, 2, 1]: 'bap'}
)
the terminal shows TypeError
TypeError: unhashable type: 'list'
only hashable objects can be used as dictionary keys and lists are not hashable
I add TypeError to the list of Exceptions encountered
# Exceptions Encountered
# AssertionError
# TypeError
green: make it pass¶
I change the assertEqual to assertRaises
def test_make_a_dictionary_w_lists_as_keys(self):
with self.assertRaises(TypeError):
{[3, 2, 1]: 'BOOM!'}
see how to test that an Exception is raised for more details on why that worked. I cannot make a dictionary with a list as a key
test_make_a_dictionary_w_sets_as_keys¶
red: make it fail¶
I try the same thing with a set as a key
def test_make_a_dictionary_w_sets_as_keys(self):
{{3, 2, 1}: 'BOOM!'}
the terminal shows TypeError
TypeError: unhashable type: 'set'
green: make it pass¶
I add assertRaises
def test_make_a_dictionary_w_sets_as_keys(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_make_a_dictionary_w_dictionaries_as_keys¶
red: make it fail¶
I add a new test
def test_make_a_dictionary_w_sets_as_keys(self):
...
def test_make_a_dictionary_w_dictionaries_as_keys(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_make_a_dictionary_w_dictionaries_as_keys(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¶
I can use the dir function to look at the attributes and methods of dictionaries
red: make it fail¶
I add a new test
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 add unittest.TestCase.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
Note
Your results can be different because of your version of Python
def test_attributes_and_methods_of_dictionaries(self):
self.maxDiff = None
self.assertEqual(
dir(src.dictionaries.a_dict()),
[
'__class__',
'__class_getitem__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__ior__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__ne__',
'__new__',
'__or__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__ror__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'clear',
'copy',
'fromkeys',
'get',
'items',
'keys',
'pop',
'popitem',
'setdefault',
'update',
'values'
]
)
the test passes. I make a TODO list with the names that do not have double underscores (__)
'clear',
'copy',
'fromkeys',
'get',
'items',
'keys',
'pop',
'popitem',
'setdefault',
'update',
'values'
# Exceptions Encountered
# AssertionError
# TypeError
test_clear_empties_a_dictionary¶
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())
the terminal shows green. The clear method returns None
red: make it fail¶
I add an assertion to see what changed in the dictionary
self.assertIsNone(a_dictionary.clear())
self.assertEqual(a_dictionary, {'key': 'value'})
the terminal shows AssertionError
AssertionError: {} != {'key': 'value'}
the clear method empties the dictionary
green: make it pass¶
I change the values to match
self.assertEqual(a_dictionary, {})
the test passes. {}
is how Python represents an empty dictionary
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, {})
the test is still passing
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):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.clear())
self.assertEqual(a_dictionary, {})
def test_copy(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.copy())
the terminal shows AssertionError
AssertionError: {'key': 'value'} is not None
the copy method returns a copy of the dictionary
green: make it pass¶
I change the assert method then add the expected value
def test_copy(self):
a_dictionary = {'key': 'value'}
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'})
the test is still green
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 in to a tuple
self.assertIsNone(a_dictionary.fromkeys((0, 1, 2, 3)))
the terminal shows AssertionError
AssertionError: {0: None, 1: None, 2: None, 3: None} is not None
the fromkeys <https://docs.python.org/3/library/stdtypes.html#dict.fromkeys> method returns a dictionary that uses the iterable given as keys with default values of None. I change the assertion then add the expected values
def test_fromkeys(self):
a_dictionary = {'key': 'value'}
self.assertEqual(
a_dictionary.fromkeys((0, 1, 2, 3)),
{0: None, 1: None, 2: None, 3: None}
)
the test passes
refactor: make it better¶
I add an assert statement 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 it and the assertion
def test_fromkeys(self): self.assertEqual( a_dictionary.fromkeys((0, 1, 2, 3)), {0: None, 1: None, 2: None, 3: None} )
the terminal shows NameError
NameError: name 'a_dictionary' is not defined
I change the call to use the dict constructor
def test_fromkeys(self): self.assertEqual( dict.fromkeys((0, 1, 2, 3)), {0: None, 1: None, 2: None, 3: None} )
the test passes
I rename the test
def test_fromkeys_makes_a_dictionary_from_an_iterable(self): self.assertEqual( dict.fromkeys((0, 1, 2, 3)), {0: None, 1: None, 2: None, 3: None} )
still green
I remove fromkeys from the TODO list
'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_get_value_of_key_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('key'))
the terminal shows AssertionError
AssertionError: 'value' is not None
the get method returns the value for the key it is given from the dictionary
I change the assertion then add the expected value
def test_get(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.get('key'), 'value')
the test passes
refactor: make it better¶
I add an assertion to see if the dictionary changed
self.assertEqual(a_dictionary.get('key'), 'value') self.assertEqual(a_dictionary, {})
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}
it stayed the same
I remove the new statement, I want to see what happens when I give the get method a key that is not in the dictionary
self.assertEqual(a_dictionary.get('key'), 'value') self.assertEqual(a_dictionary.get(0), {})
the terminal shows AssertionError
AssertionError: None != {}
the get method returns None when the given key is not in the dictionary. I remove the expectation and change the assertion
self.assertIsNone(a_dictionary.get(0))
the test passes
I change the name of the test
def test_get_value_of_key_from_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.get('key'), 'value') self.assertIsNone(a_dictionary.get(0))
the test is still green
I remove get from the TODO list
'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_pop_removes_key_and_returns_its_value_from_a_dictionary¶
red: make it fail¶
I add a test for the next method
def test_get_value_of_key_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
the items methods returns a dict_items
object that contains the keys and values of the dictionary
green: make it pass¶
I copy and paste the value from the terminal
self.assertIsNone(a_dictionary.items(), dict_items([('key', 'value')]))
the terminal shows AssertionError
NameError: name 'dict_items' is not defined
the dict_items
object has a list that contains a tuple, I use that
self.assertIsNone(a_dictionary.items(), [('key', 'value')])
the terminal shows AssertionError
AssertionError: dict_items([('key', 'value')]) is not None : [('key', 'value')]
I change the assertion and wrap the call in the list constructor
self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the test passes
refactor: make it better¶
I rename the test
def test_pop_removes_key_and_returns_its_value_from_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(list(a_dictionary.items()), [('key', 'value')])
the test is still green
I remove items from the TODO list
'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
test_keys_of_a_dictionary¶
red: make it fail¶
I add the next test
def test_pop_removes_key_and_returns_its_value_from_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 is like test_pop_removes_key_and_returns_its_value_from_a_dictionary
green: make it pass¶
I copy and paste the values from the terminal then change the assertion
def test_keys(self):
a_dictionary = {'key': 'value'}
self.assertEqual(a_dictionary.keys(), dict_keys(['key']))
the terminal shows NameError
NameError: name 'dict_keys' is not defined
the keys method returns dict_keys
object that has the keys of the dictionary. I change the expectation to a list and use the list constructor to wrap the call
self.assertEqual(list(a_dictionary.keys()), ['key'])
the test passes
refactor: make it better¶
I rename the test
def test_keys_of_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertEqual(list(a_dictionary.keys()), ['key'])
the test is still green
I remove keys from the TODO list
'pop', 'popitem', 'setdefault', 'update', 'values'
test_pop_removes_and_returns_key_w_value_from_a_dictionary¶
red: make it fail¶
I add a test for the next method
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
def test_pop(self):
a_dictionary = {'key': 'value'}
self.assertIsNone(a_dictionary.pop(0))
the terminal shows KeyError
KeyError: 0
I change the assertion to assertRaises
def test_pop(self):
a_dictionary = {'key': 'value'}
with self.assertRaises(KeyError):
a_dictionary.pop(0)
calling the pop method with a key that is not in the dictionary raises a KeyError
refactor: make it better¶
I add another assertion
def test_pop(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.pop('key')) with self.assertRaises(KeyError): a_dictionary.pop(0)
the terminal shows AssertionError
AssertionError: 'value' is not None
the pop method returns the value from the dictionary for the key it is given
I change the assertion to assertEqual and paste the value from the terminal
a_dictionary = {'key': 'value'} self.assertEqual(a_dictionary.pop('key'), 'value')
the test passes
I add another assertion to see what happens 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 from the dictionary for the key it is given
I change the value expectation to match
self.assertEqual(a_dictionary, {})
the test passes
I rename the test
def test_pop_removes_and_returns_key_w_value_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(0)
the test is still passings
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_and_returns_key_w_value_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 change the assertion and paste the value from the terminal
a_dictionary = {'key': 'value'}
self.assertEqual(a_dictionary.popitem(), ('key', 'value'))
the test passes
refactor: make it better¶
I want to know what the popitem method does 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 given from the dictionary
I change the value
self.assertEqual(a_dictionary, {})
the test passes
I add another assertion
self.assertEqual(a_dictionary, {}) self.assertEqual(a_dictionary.popitem(), None)
the terminal shows KeyError
KeyError: 'popitem(): dictionary is empty'
I change the assertion to assertRaises
self.assertEqual(a_dictionary, {}) with self.assertRaises(KeyError): a_dictionary.popitem()
the test passes
this operation does not take input, I change the dictionary to see how it behaves
a_dictionary = { 'key1': 'value1', 'key2': 'value2' }
the terminal shows AssertionError
AssertionError: Tuples differ: ('key2', 'value2') != ('key', 'value')
I change the expectation to match
self.assertEqual( a_dictionary.popitem(), ('key2', 'value2') )
the terminal shows AssertionError
AssertionError: {'key1': 'value1'} != {}
I change the value to match
self.assertEqual(a_dictionary, {'key1': 'value1'})
the terminal shows AssertionError
AssertionError: KeyError not raised
I change the assertRaises to assertEqual
self.assertEqual( a_dictionary.popitem(), ('key1', 'value1') )
popitem returns the last key-value pair in the dictionary
I add another call to the method that should fail
self.assertEqual( a_dictionary.popitem(), ('key1', 'value1') ) a_dictionary.popitem()
the terminal shows KeyError
KeyError: 'popitem(): dictionary is empty'
I add assertRaises
self.assertEqual( a_dictionary.popitem(), ('key1', 'value1') ) with self.assertRaises(KeyError): a_dictionary.popitem()
the test passes
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', 'key2': 'value2' } self.assertEqual( a_dictionary.popitem(), ('key2', 'value2') ) self.assertEqual(a_dictionary, {'key1': 'value1'}) self.assertEqual( a_dictionary.popitem(), ('key1', 'value1') ) with self.assertRaises(KeyError): a_dictionary.popitem()
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 changed in 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 add another test to see what happens when the key is already in the dictionary
self.assertEqual( a_dictionary, { 'key': 'value', 0: None, } ) self.assertIsNone(a_dictionary.setdefault('key'))
the terminal shows AssertionError
AssertionError: 'value' is not None
setdefault returns the value for the key in a dictionary when the key already exists
I paste the value from the terminal then change the assertion to assertEqual
self.assertEqual( a_dictionary.setdefault('key'), 'value' )
the test passes
I rename the test
def test_setdefault_adds_key_w_a_default_value_to_a_dictionary(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.setdefault(0)) self.assertEqual( a_dictionary, { 'key': 'value', 0: None, } ) self.assertEqual( a_dictionary.setdefault('key'), 'value' )
the test is still green
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_update(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.update())
I add an assertion to see what it does to the dictionary
self.assertIsNone(a_dictionary.update()) self.assertEqual(a_dictionary, {})
the terminal shows AssertionError
AssertionError: {'key': 'value'} != {}
the dictionary stayed the same, the test has to get better
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 check the Python documentation for the update method and see that it takes a dictionary as input. I add one to the call
def test_update(self): a_dictionary = {'key': 'value'} self.assertIsNone(a_dictionary.update({'key1': 'value1'})) self.assertEqual(a_dictionary, {'key': 'value'})
the terminal shows AssertionError
AssertionError: {'key': 'value', 'key1': 'value1'} != {'key': 'value'}
the update method adds the key-value pairs from the given dictionary to the existing one
I change the expectation to match the values from the terminal
self.assertIsNone(a_dictionary.update({'key1': 'value1'})) self.assertEqual( a_dictionary, { 'key': 'value', 'key1': 'value1' } )
the test passes
I add another assertion
self.assertIsNone(a_dictionary.update({'key1': 'value1'})) self.assertIsNone(a_dictionary.update(another_key='another value'))
the terminal shows AssertionError
AssertionError: {'key': 'value', 'key1': 'value1', 'another_key': 'another value'} != {'key': 'value', 'key1': 'value1'}
the update method accepts keyword arguments. I change the values to match
self.assertEqual( a_dictionary, { 'key': 'value', 'key1': 'value1', 'another_key': 'another value' } )
the test passes
I want to know what would happen if the key already exists in the dictionary
self.assertIsNone(a_dictionary.update(another_key='another value')) self.assertIsNone(a_dictionary.update(key='new value'))
the terminal shows AssertionError
AssertionError: {'key': 'new value', 'key1': 'value1', 'another_key': 'another value'} != {'key': 'value', 'key1': 'value1', 'another_key': 'another value'}
the update method changes the value for an existing key in a dictionary. I change the expectation to match
self.assertEqual( a_dictionary, { 'key': 'new value', 'key1': 'value1', '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({'key1': 'value1'})) self.assertIsNone(a_dictionary.update(another_key='another value')) self.assertIsNone(a_dictionary.update(key='new value')) self.assertEqual( a_dictionary, { 'key': 'new value', 'key1': 'value1', '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_pop_removes_key_and_returns_its_value_from_a_dictionary and test_keys_of_a_dictionary
green: make it pass¶
I change the assertIsNone to assertEqual and change the expectation to a list
a_dictionary = {'key': 'value'}
self.assertEqual(a_dictionary.values(), ['value'])
the terminal shows AssertionError
AssertionError: dict_values(['value']) != ['value']
I wrap the call in the list constructor
self.assertEqual(list(a_dictionary.values()), ['value'])
the test passes
refactor: make it better¶
I add more keys and values to the dictionary
def test_values(self): a_dictionary = { 'a_key': 'a value', 'another_key': 'another value', }
the terminal shows AssertionError
AssertionError: Lists differ: ['a value', 'another value'] != ['value']
I change the values
self.assertEqual( list(a_dictionary.values()), ['a value', 'another value'] )
the test passes
I rename the test
def test_values_of_a_dictionary(self): a_dictionary = { 'a_key': 'a value', 'another_key': 'another value', } self.assertEqual( list(a_dictionary.values()), ['a value', 'another value'] )
the test passes
I remove values from the TODO list
test_key_error¶
red: make it fail¶
I add a test
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['key_not_in_dictionary'], 'value')
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['key_not_in_dictionary']
the test passes
I know from test_popitem_removes_and_returns_last_key_value_pair_from_a_dictionary that I get KeyError when I call the method on an empty dictionary
with self.assertRaises(KeyError): a_dictionary['key_not_in_dictionary'] {}.popitem()
the terminal shows KeyError
KeyError: 'popitem(): dictionary is empty'
I add assertRaises
with self.assertRaises(KeyError): a_dictionary['key_not_in_dictionary'] with self.assertRaises(KeyError): {}.popitem()
I also get KeyError when I call pop with a key that does not exist in the dictionary
with self.assertRaises(KeyError): {}.popitem() a_dictionary.pop('key_not_in_dictionary')
the terminal shows KeyError
KeyError: 'key_not_in_dictionary'
I add assertRaises
with self.assertRaises(KeyError): {}.popitem() with self.assertRaises(KeyError): a_dictionary.pop('key_not_in_dictionary')
I can use the get method to avoid the KeyError when the key does not exist in a dictionary
with self.assertRaises(KeyError): a_dictionary.pop('key_not_in_dictionary') self.assertEqual( a_dictionary.get('key_not_in_dictionary'), 'value' )
the terminal shows AssertionError
AssertionError: None != 'value'
I remove the expected value and change assertEqual to assertIsNone
with self.assertRaises(KeyError): a_dictionary.pop('key_not_in_dictionary') self.assertIsNone(a_dictionary.get('key_not_in_dictionary'))
the test is green again
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?