[Tutor] mock
Alex Kleider
akleider at sonic.net
Fri Jan 22 15:27:24 EST 2016
Some weeks (perhaps months) ago, I posted a question about testing
and got many responses but had trouble grasping the concepts
so I settled on the suggestion that I thought would be the easiest
to implement (using unittest.mock.) Here it is-
"""
from Peter Otten:
I find Ben's example instructive, but when you're just starting you
might prefer a simpler approach:
import unittest
from unittest import mock
import mycode
class TestCollectData(unittest.TestCase):
def test(self):
with mock.patch(
"builtins.input",
side_effect=["foo", "bar", "baz"]):
self.assertEqual(
mycode.collect_data(),
dict(first="foo", last="bar", phone="baz"))
if __name__ == "__main__":
unittest.main()
"""
I've successfully implemented mock.patch parameters but don't
understand how to implement the parameters for the assertEqual
call as it pertains to my particular situation.
My current code sort of does the job but determinating success or
failure is not really automated.
It's Python 3 on Ubuntu 14.4LTS.
My test code and the tested code follow. Any suggestions would be
most welcome. Thanks in advance.
Alex
Test Code:
#!../../venv/bin/python
# -*- coding: utf-8 -*-
# vim: set file encoding=utf-8
"""
Attempt to automate testing of menu module.
"""
import unittest
from unittest import mock
import menu
class MenuTests(unittest.TestCase):
def test_create_new(self):
with mock.patch("builtins.input",
side_effect=['1', 'testentity', '', '0']):
menu.menu()
if __name__ == '__main__': # code block to run the application
unittest.main()
Tested code:
#!../../venv/bin/python
# -*- coding: utf-8 -*-
# vim: set file encoding=utf-8
"""
A simple menu model used to format a question
about how to test using unittest.mock.
"""
class Entities(object):
"""
Keep track of the entities including a default.
Expect only one instance which will be a global.
"""
def __init__(self, list_of_entities, default=''):
self._list = list_of_entities
self.default = default
def get_default(self):
return self.default
def reset_default(self, default=''):
self.default = default
def get_list(self):
return self._list
def add(self, new_entity, set_default=False):
"""
Adds another entity returning it to signal success.
Returns None if entity is unacceptable.
"""
if (not new_entity in self._list
and new_entity.isalnum()
and new_entity[0:1].isalpha()):
self._list.append(new_entity)
if set_default:
self.reset_default(new_entity)
return new_entity
else:
print("Failing to add an invalid entity: '{}'."
.format(new_entity))
def get_new_entity(self):
"""
Prompts user for a new entity which, if valid, is
returned after being appended to list and set as default.
Returns None if fails to create a new entity.
"""
while True:
new_entity = input("Pick name for new entity: ")
if not new_entity: return
if new_entity != self.add(new_entity, set_default=True):
continue
else:
return new_entity
def remove(self, entity2remove):
if not entity2remove in self.get_list():
print("Can't remove '{}': not in the list."
.format(entity2remove))
return
if entity2remove == self.get_default():
self.reset_default()
self._list = [entity for entity in self._list
if entity!=entity2remove]
def show_listing(self):
"""
Returns a string listing the available entities.
Empty string if there are no entities.
"""
return ''.join(["\n\t {}".format(entity)
for entity in self.get_list()])
def entity_choice(self, set_default=False):
"""
Prompts the user to choose from the list.
Returns a valid choice or None.
Can optionally set the default to the chosen entity.
"""
list_of_entities= self.get_list()
if not list_of_entities:
print("There are no entities from which to choose.")
return
default_line = ''
if self.default:
default_line = ("\n\t_: Default is '{}', just hit enter."
.format(self.default))
menu = ('\n'.join(["\t{}: {}".format(n, entity)
for (n, entity) in enumerate(list_of_entities, 1)])
+ default_line)
while True:
option = input(
"""Choose one of the following:
{}
\t0: to exit.
Pick an entity: """.format(menu))
default = self.get_default()
if (option=='' or option=='_') and default:
return default
try:
option = int(option)
except ValueError:
print("Invalid option: {}! (It must be an integer.)"
.format(option))
continue
entity_list = self.get_list()
if option in range(1, len(entity_list) + 1):
choice = entity_list[option - 1]
if set_default:
self.default = choice
return choice
elif option == 0:
return None
else:
print("Invalid entry- try again ('0' to quit.)")
def create_new(option, entities):
"""
A main menu response function.
"""
print("Picked '{}. Create a new entity.'".format(option))
entity = entities.get_new_entity()
if entity:
print(
"Entity '{}' successfully created (and set as default.)"
.format(entity))
work_with(entity)
else:
print("Aborting entity creation.")
def choose_existing(option, entities):
"""
A main menu response function.
"""
print("Picked '{}'. Choose an entity."
.format(option))
choice = entities.entity_choice(set_default=True)
if choice:
work_with(choice)
def delete_option(option, entities):
"""
A main menu response function.
"""
print("Picked '{}. Delete an existing entity.'".format(option))
while True:
entity = entities.entity_choice()
if not entity:
print("Entity deletion aborted.")
return
y_n = input("About to delete entity '{}', ARE YOU SURE? "
.format(entity))
if y_n and y_n[0] in 'Yy':
print("Deleting entity '{}'.".format(entity))
entities.remove(entity)
else:
print("No deletion being done.")
break
def work_with(entity):
"""
Provides an interface stub for once an entity has been selected.
"""
_ = input("Stub of code to work with '{}' entity goes here."
.format(entity))
def menu():
"""
Provides the top level user interface.
"""
entities = Entities(["ent1", "ent2", "ent3"], "ent2")
while True:
listing = entities.show_listing()
if listing:
listing = (
"""\n( Currently existing entities are: {} )"""
.format(listing))
option = input("""
Main Menu:{}
1. Create a new entity.
2. Choose an existing entity.
9. Delete an entity.
0. Exit
Choice: """
.format(listing))
print("Main Menu choice: {}".format(option))
if option in ('', '_', '0'):
return
try:
option = int(option)
except ValueError:
print(
"Invalid main menu choice: {} (must be an integer.)"
.format(option))
continue
if option == 1:
entity = create_new(option, entities)
elif option == 2:
entity = choose_existing(option, entities)
elif option == 9:
delete_option(option, entities)
entity = ''
else:
print("BAD CHOICE '{}'- try again....".format(option))
entity = None
if entity:
work_with(entity)
if __name__ == "__main__":
menu()
~
More information about the Tutor
mailing list