Python 内部函数中的模拟默认参数值
我有以下(简化的)代码:Python 内部函数中的模拟默认参数值,python,python-unittest,python-mock,pytest-mock,Python,Python Unittest,Python Mock,Pytest Mock,我有以下(简化的)代码: def get_redis() 返回redis_实例 定义栏(键、值、redis=get_redis()) redis.set(键、值) def foo() 条(“键”,值) 在我的测试中,我想模拟函数get\u redis来返回fakeredis.fakestritredis()的实例,所以我这样做了 def test_foo(mocker): mocker.patch(“app.main.get_redis”,return_value=fakeredis.Fake
def get_redis()
返回redis_实例
定义栏(键、值、redis=get_redis())
redis.set(键、值)
def foo()
条(“键”,值)
在我的测试中,我想模拟函数get\u redis
来返回fakeredis.fakestritredis()
的实例,所以我这样做了
def test_foo(mocker):
mocker.patch(“app.main.get_redis”,return_value=fakeredis.FakeStrictRedis())
foo()
模拟函数无效,foo
函数尝试使用main中的get\u redis函数连接到real redis
如果我用这种方式写的话
def条(键、值)
redis=get_redis()
redis.set(键、值)
这是可行的,但我可以将redis作为默认值传递。如何进行模拟?我只需对
条
函数稍作修改,如下所示,以便在应用模拟之前不会调用您的函数:
def bar(key, value, redis=get_redis)
if callable(redis):
redis = redis()
redis.set(key, value)
以这种方式编写函数意味着您的模拟将在调用函数时应用,而不是在启动时应用任何模拟。简而言之,以这种方式编写
bar
可以确保get\u redis
的返回,它将在每次调用函数时通过bar
函数进行传播。模拟没有问题,但您似乎误解了默认参数值的工作方式。如中所述,在执行函数定义时计算默认参数值
在您的情况下,这意味着在定义了bar
时,已经调用了原始的get\u redis
:
定义栏(键、值、redis=get_redis()):
当pytest
导入您的模块时,即在执行test\u foo
之前执行此语句,因此在测试中模拟get\u redis
没有效果,因为那时已经太晚了
要使默认工厂函数可模拟,请使用None
作为默认值,并使函数调用工厂,除非在调用中指定了另一个值:
def条(键、值、redis=None)
redis=redis或get_redis()
redis.set(键、值)
我根本不会嘲笑你foo
需要一个Redis实例,如果只是传递到bar
,那么将其作为一个参数。然后你可以简单地将你的假实例作为参数传递,而不是修补任何东西。我不能将redis实例传递给foo
,因为这是一种RPC方法。我想,另一种方法是将redis作为全局变量。这不起作用,它仍然调用原始的get\u redis
,因为默认值的计算结果仍然是原始函数。