在内部函数中模拟默认参数值
Mock default parameter value in inner function
我有以下(简化的)代码:
def get_redis()
return redis_instance
def bar(key, value, redis=get_redis())
redis.set(key, value)
def foo()
bar("key", value)
在我的测试中,我想将函数 get_redis
模拟为 return fakeredis.FakeStrictRedis()
的一个实例,所以我这样做了
def test_foo(mocker):
mocker.patch("app.main.get_redis", return_value=fakeredis.FakeStrictRedis())
foo()
mock 函数无效,foo
函数尝试使用来自 main 的 get_redis 函数连接到真正的 redis。
如果我这样写就可以了
def bar(key, value)
redis=get_redis()
redis.set(key, value)
这可行,但我可以将 redis 作为默认值传递。我该如何嘲笑?
我将按如下方式稍微修改 bar
函数,这样您的函数就不会在应用模拟之前被调用:
def bar(key, value, redis=get_redis)
if callable(redis):
redis = redis()
redis.set(key, value)
以这种方式编写函数意味着您的模拟将在函数被调用时应用,而不是在启动时应用任何模拟之前。简而言之,以这种方式编写 bar
,确保 get_redis
的 return 每次调用函数时都会通过您的 bar
函数传播。
您的模拟没有任何问题,但您似乎误解了默认参数值的工作原理。如 the Python Language Reference 中所述, 执行函数 定义 时会计算默认参数值 。
在您的情况下,这意味着在定义 bar
时已经调用了原始 get_redis
:
def bar(key, value, redis=get_redis()):
此语句在 pytest
导入您的模块时执行,即在执行 test_foo
之前执行,因此在测试中模拟 get_redis
没有效果,因为到那时已经太晚了.
要使 default-supplying 工厂函数可模拟,请使用 None
作为默认值并使函数调用工厂函数,除非在调用中指定了另一个值:
def bar(key, value, redis=None)
redis = redis or get_redis()
redis.set(key, value)
我有以下(简化的)代码:
def get_redis()
return redis_instance
def bar(key, value, redis=get_redis())
redis.set(key, value)
def foo()
bar("key", value)
在我的测试中,我想将函数 get_redis
模拟为 return fakeredis.FakeStrictRedis()
的一个实例,所以我这样做了
def test_foo(mocker):
mocker.patch("app.main.get_redis", return_value=fakeredis.FakeStrictRedis())
foo()
mock 函数无效,foo
函数尝试使用来自 main 的 get_redis 函数连接到真正的 redis。
如果我这样写就可以了
def bar(key, value)
redis=get_redis()
redis.set(key, value)
这可行,但我可以将 redis 作为默认值传递。我该如何嘲笑?
我将按如下方式稍微修改 bar
函数,这样您的函数就不会在应用模拟之前被调用:
def bar(key, value, redis=get_redis)
if callable(redis):
redis = redis()
redis.set(key, value)
以这种方式编写函数意味着您的模拟将在函数被调用时应用,而不是在启动时应用任何模拟之前。简而言之,以这种方式编写 bar
,确保 get_redis
的 return 每次调用函数时都会通过您的 bar
函数传播。
您的模拟没有任何问题,但您似乎误解了默认参数值的工作原理。如 the Python Language Reference 中所述, 执行函数 定义 时会计算默认参数值 。
在您的情况下,这意味着在定义 bar
时已经调用了原始 get_redis
:
def bar(key, value, redis=get_redis()):
此语句在 pytest
导入您的模块时执行,即在执行 test_foo
之前执行,因此在测试中模拟 get_redis
没有效果,因为到那时已经太晚了.
要使 default-supplying 工厂函数可模拟,请使用 None
作为默认值并使函数调用工厂函数,除非在调用中指定了另一个值:
def bar(key, value, redis=None)
redis = redis or get_redis()
redis.set(key, value)