我正在尝试为我的 main 模块和main()
方法编写一个单元测试(或根据需要将其称为集成测试)。
它看起来像这样:
# main.py in mymodule
# some imports...
def main() -> None:
# args is a result of argparse parsing
try:
if args.type == 'a':
from mymodule import a
a.run()
elif args.type == 'b'
from mymodule import b
b.run()
# elif ...
else:
raise RuntimeError('Unknown type ' + args.type)
except (RuntimeError, FileNotFoundError, ...) as e:
# some logging
sys.exit(1)
# some other logging
我尝试通过以下方式模拟/修补模块:
def dummy_run():
# just do nothing here
def test_main_a(self):
import mymodule.a
mymodule.a.run = dummy_run
os.system('python3 mymodule.main a')
和
def test_main_a(self):
# patch is imported as from unittest.mock import patch
with patch('mymodule.a.run', return_value=None):
os.system('python3 mymodule.main a')
和
def test_main_a(self):
# patch is imported as from unittest.mock import patch
with patch('mymodule.a.run') as run_mocked:
run_mocked.return_value = None
os.system('python3 mymodule.main a')
和
@patch('mymodule.a.run')
def test_main_a(self, a_mock):
a_mock.return_value = None
os.system('python3 mymodule.main a')
但是所有这些方式都不会模拟/修补mymodule.a.run
方法,而该方法最终以调用的真实方法结束。
当我尝试修补mymodule.main.a.run
或mymodule.main.mymodule.a.run
时,我只有ModuleNotFoundError
个。阅读Where to patch部分后,我尝试了这些目标。
老实说,我真的不了解修补程序的问题所在,因为我是在导入模块mymodule.a
并调用run()
之前进行修补的(因为这仅在{{1}之后}部分)。非常感谢您的帮助!
答案 0 :(得分:1)
修补和模拟仅在同一解释器中起作用,但是您对os.system('python [...]')
的调用将在新解释器中运行main
函数。相反,您可能想直接调用main
函数。这可能涉及修补某些sys
对象,例如sys.exit
和sys.argv
。
但是,通常的做法是为args
函数提供可选的main
参数:
def main(args=None):
parser = argparse.ArgumentParser()
parser.add_argument('type')
namespace = parser.parse_args(args)
if namespace.type == 'a':
from mymodule import a
a.run()
sys.exit()
这样,可以轻松地注入和测试命令行参数:
def test_main_a():
with patch('mymodule.a.run') as run_mocked:
main(['a'])
此外,pytest.raises上下文可用于管理对sys.exit
的调用:
def test_main_a():
with patch('mymodule.a.run') as run_mocked:
with pytest.raises(SystemExit):
main(['a'])