模拟 function/object 和基于 input/conditions 的 return 值

Mocking a function/object, and return values based on input/conditions

我面临以下情况。

我有以下源码

#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)

我想测试函数 order_names,我想模拟对 get_name_by_id(id) 的调用。

假设 get_name_by_id(id) 将针对各种 id 多次调用,是否可以根据输入创建一个 returns 值的模拟?

例如:

#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"

以上测试代码是要实现的行为类型的示例,因为 get_name_by_id() 不是 dict return 类型。

干杯!

您基本上需要 get_name_by_id 的替代实现,而不仅仅是新的 return 值。

# 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"

如果 get_name_by_id 更复杂,您也可以考虑修补网络调用,让 get_name_by_id 运行 保持原样。

# 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"

现在,当您调用 order_names 时,它会调用 get_name_by_idget_name_by_id 将使用您对 make_some_network_call 的替代定义。