Python 使用decorator模拟函数默认值

Python 使用decorator模拟函数默认值,python,mocking,Python,Mocking,按照中的方法,我可以使用下面的方法覆盖函数的默认值,请参见test\u foo\u defaults main.py: def bar(x): return x * 2 def foo(a, b=bar, c=4): return f'{a} {b(a)} {c}' main_test.py import unittest from unittest import mock from unittest.mock import MagicMock import main de

按照中的方法,我可以使用下面的方法覆盖函数的默认值,请参见
test\u foo\u defaults

main.py:

def bar(x):
    return x * 2

def foo(a, b=bar, c=4):
    return f'{a} {b(a)} {c}'
main_test.py

import unittest
from unittest import mock
from unittest.mock import MagicMock
import main

def test_foo():
    assert '3 6 4' == main.foo(3)

def test_foo_defaults():
    m = MagicMock()
    m.return_value = 12
    with mock.patch.object(main.foo, '__defaults__', (m, 7)):
        assert '3 12 7' == main.foo(3)

@mock.patch.object(main.foo.__defaults__, 0)
def test_foo_defaults_2(m):
    m.return_value = 12
    assert '3 12 5' == main.foo(3)
但是,我希望能够执行类似于
test\u foo\u defaults2
的操作,其中我只覆盖一个默认参数,并将其句柄作为模拟传递给我的测试函数<很遗憾,代码>测试\u foo\u defaults2无法正常工作,但失败的原因是:
类型错误:getattr():属性名称必须为字符串

有什么解决办法吗?

您是否尝试过:

@mock.patch.object(main.foo, '__defaults__', (5,))
def test_foo_defaults():
    assert '3 5' == main.foo(3)

文档中说,
unittest.mock.patch.object
可以用作装饰器。

new\u callable
参数可以用来替换初始化注入的模拟值的函数

new_callable允许您指定将被调用以创建新对象的其他类或可调用对象。默认情况下,AsyncMock用于异步函数,MagicMock用于其余函数

资料来源:

def init_mock_defaults():
返回(MagicMock(返回值=6),5)
@object(main.foo,“\uuuuu默认值”\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu默认值),new\u callable=init\u mock\u
def测试_foo_默认值_2(默认值):
默认值[0]。返回值=12
断言'3125'==main.foo(3)
或使用内嵌lambda:

@mock.patch.object(
main.foo,“\uuuuu默认值”,
new_callable=lambda:(MagicMock(返回值=6),5)
)
def测试_foo_默认值_2(默认值):
默认值[0]。返回值=12
断言'3125'==main.foo(3)

老实说,这两种解决方案看起来都很令人不安。

@Attila Viniczai你的回答让我了解了其中的一部分。另一个目的是避免在
\uuuuu defaults\uuuuu
中指定第二个元素。这对我很有用:

def init_mocked_defaults(**kwargs):
    r = list(main.foo.__defaults__)
    r[0] = MagicMock()
    return tuple(r)                                                                                                                                        
 
@mock.patch.object(main.foo, "__defaults__", new_callable=init_mocked_defaults)
def test_foo_defaults_2(defaults):
    defaults[0].return_value = 12
    assert '3 12 4' == main.foo(3)

很抱歉,我最初的问题不是很清楚,请看更新版本。