【问题标题】:Mocking functions in python called from a dictionary从字典调用的python中的模拟函数
【发布时间】:2021-08-17 12:38:16
【问题描述】:

我对下面的代码有疑问。我想模拟不同文件中的函数以在 FUNCTION_MAPPING 部分进行单元测试。

import module.module2 as module_name

FUNCTION_MAPPING = {
1: module_name.foo,
2: module_name.foo2,
3: module_name.foo3
}

def my_func(number):
    function_call = FUNCTION_MAPPING[number]
    result = function_call()
    return result

由于某种原因,我无法模拟这些功能。我已经尝试了我所知道的所有可能的方法。如果可能的话,我不想更改上面的代码。

foo、foo2 和 foo3 内部代码可以是任何 print(1)、print(2) 等

单元测试代码:

@patch("module_of_the_code_above.module_name.foo",return_value="Test")
def test_my_func(self,mocked_foo):
    result = my_func(1)
    nose_tools.assert_equal(result,"Test")

【问题讨论】:

  • 你有错误吗? foo、foo2、foo3函数的代码是什么?
  • 请提供一个最小的工作示例,包括module.module2 的代码和您的单元测试。
  • module.module2 只是函数 foo、foo2、foo3 所在的模块。这些函数的内部代码与问题无关。
  • 它是相关的,因为导入函数的方式很重要 - from foo import barimport foo.bar 在您的代码和单元测试中具有不同的命名空间结果。请提供复制您的错误的确切代码(包括导入的函数和单元测试),以便我们对其进行测试,而不是盲目地假设您是如何定义事物的。
  • 我已经更新了这个问题,但这是我能做的最好的。我不能分享原始代码:)

标签: python unit-testing mocking


【解决方案1】:

如果你使用 MagicMock,简单的两个选项:

这种情况的问题是,当您导入模块时,会创建带有查找的字典并引用“module_name.foo”,因此全局级别的任何修补/模拟都不会影响该显式映射,您必须在该结构上替换/包装它。

....

# in you test manually replace the function mapping with either new
# functions you define, but I prefer MagicMock as it allows you to get
# all kinds of goodies.
# This is necessary as the dict for the function lookup is probably already
# initialize before any mocking can take place (as you include the module)
# and so even patching the function globally will not affect that lookup

# You can use MagicMock so that your original function is not used..
FUNCTION_MAPPING['1'] = mock.MagicMock()
FUNCTION_MAPPING['2'] = mock.MagicMock()
FUNCTION_MAPPING['3'] = mock.MagicMock()

# Or

# if you just want to spy/keep stats but still call the original function, you will 
# need to do something like 
FUNCTION_MAPPING['1'] = mock.Mock(wraps=FUNCTION_MAPPING['1')

# then you can all the great things that you can do with mock. 
assert FUNCTION_MAPPING['1'].call_counts == 3

PS:没有时间测试/审查 this 的确切语法,但希望这能指引您正确的方向。

【讨论】:

  • 很高兴它有帮助:)
【解决方案2】:

您应该分配函数(不带括号)而不是函数的结果 - {1: func}

def hello():
    print('Hello!')

def text(text):
    print(text)

function_map = {
    1: hello,
    2: text
}

func1 = function_map[1]
func1()

func2 = function_map[2]
func2('ABC123')

输出:

Hello!
ABC123

使用导入时:

import math

function_map = {
    'factorial': math.factorial,
    'gcd': math.gcd
}

func1 = function_map['factorial']
print(func1(5))

func2 = function_map['gcd']
print(func2(5, 25))

【讨论】:

  • OP 的问题似乎与从字典中调用函数无关,而是与单元测试时模拟字典有关。
  • 问题是我不能模拟字典里面的函数。
猜你喜欢
  • 2019-11-02
  • 2023-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多