I am facing the following scenario.
I have the following source code
#file:[src/my_module.py]
def order_names(unordered_input: List) -> str:
# function that orders a list of names
...
if(is_ID(unordered_input[i])):
id = unordered_input[i]
name = get_name_by_id(id)
...
def get_name_by_id(id) -> str:
# function that returns a name, based on an ID, through a Rest API call
return make_some_network_call(id)
I want to test the function order_names
, and I want to mock the calls to get_name_by_id(id)
.
Assuming that the get_name_by_id(id)
will be called many times for various id
s, can a mock be created that returns values according to the input?
For example:
#file:[test/test_my_module.py]
from unittest import mock
from my_module import order_names
@mock.patch("src.my_module.get_name_by_id", return_value={"3": "Mark", "4": "Kate", "5":"Alfred"})
def test_order_names():
ordered_names = order_names(["3", "4", "Suzan", "5"])
assert ordered_names == "Alfred, Kate, Mark, Suzan"
The above test code is an example of the type of the behavior to be achieved, since get_name_by_id()
is not a dict
return type.
Cheers!
You basically need an alternate implementation of get_name_by_id
, not just a new return value.
# Adjust the definition to behave the same when the lookup fails
def get_name_locally(id):
return {"3": "Mark", "4": "Kate", "5":"Alfred"}.get(id)
def test_order_names():
with mock.patch('src.my_module.get_name_by_id', get_name_locally):
ordered_names = order_names(["3", "4", "Suzan", "5"])
assert ordered_names = "Alfred, Kate, Mark, Suzan"
If get_name_by_id
is more complicated, you could also consider patching the network call instead and letting get_name_by_id
run as-is.
# The same as get_name_locally above, but only because
# get_name_by_id and make_some_network_call are functionally
# identical as far as the question is written.
def network_replacement(id):
return {"3": "Mark", "4": "Kate", "5":"Alfred"}.get(id)
def test_order_names():
with mock.patch('src.my_module.make_some_network_call', network_replacement):
ordered_names = order_names(["3", "4", "Suzan", "5"])
assert ordered_names = "Alfred, Kate, Mark, Suzan"
Now when you call order_names
, and it calls get_name_by_id
, your alternate definition of make_some_network_call
will be used by get_name_by_id
.