我有一个函数foo
,它调用了另一个函数get_info_from_tags
。
这是get_info_from_tags
的实现:
def get_info_from_tags(*args):
instance_id = get_instance_id()
proc = subprocess.Popen(["aws", "ec2", "describe-tags", "--filters", f"Name=resource-id,Values={instance_id}"],
stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
em_json = json.loads(out.decode('utf8'))
tags = em_json['Tags'] # tags list
results = []
for arg in args:
for tag in tags:
if tag['Key'] == arg:
results.append(tag['Value'])
return results
有一组10个可能的参数可以传递给get_info_from_tags
,我需要返回正确的数组(我不想调用aws服务,这就是我的模拟的重点,我将在字典中手动设置值。
如何模拟get_info_from_tags
,以便在我打电话时
get_info_from_tags('key1', 'key2' ...)
在foo函数中,我得到了想要的结果吗?
我已经尝试了pytest的某些功能,但是似乎我不太了解。
可能的解决方案是创建另一个函数:
def mocked_get_info_from_tags(*args):
values = []
for arg in args:
values.append(my_dictionary[arg])
return values
但是我不知道如何在测试环境中实现此替代。
谢谢。
答案 0 :(得分:0)
您可以从另一个函数中调用一个函数,然后在设置数据库后将其替换。这样,您仍然可以在代码中的任何地方调用foo.get_info_from_db('key1', 'key2' ...)
,并且在添加适当的数据库连接后,只需更改一个主要的get_info_from_db
函数实现并删除模拟
import db_connector
def mocked_get_info_from_db(*args):
values = []
for arg in args:
values.append(my_dictionary[arg])
return values
def get_info_from_db(*args):
# remove this once your database is setup
return mocked_get_info_from_db(*args)
# values = []
# for arg in args:
# values.append(db_connector.get(arg))
# return values
答案 1 :(得分:0)
unittest.mock.patch
是你的朋友。
您没有指定模块名称,因此我在其中放置了一些占位符。
from unittest.mock import patch
from <module_with_foo> import foo
from <module_with_mock> import mocked_get_info_from_tags
with patch('<module_with_foo>.get_info_from_tags', mocked_get_info_from_tags):
foo()
这会将get_info_from_tags
替换为该函数的模拟版本。替换是在模块级别完成的,因此模块<module_with_foo>
中调用get_info_from_tags
的所有内容现在都将调用您的模拟。
请注意给patch
的路径:
patch
替换模块属性的值。因此,如果您有一个带有功能moo
的模块foo
,该模块会从模块bar
调用moo2
:
# moo module
from moo2 import bar
def foo():
bar()
...从patch
的角度来看,moo.foo
呼叫moo.bar
,而不是moo2.bar
。这就是为什么您必须在使用该功能的模块而不是定义该模块的地方修补该模块。