python - 执行 python 脚本,获取其打印和日志输出并断言 unittest
问题描述
编辑:感谢@eemz 重新设计结构和使用的想法from unittest.mock import patch
,但问题仍然存在。
所以我最近偶然发现了 unittest 并且我有一个通常像这样开始的程序python run.py -config /path/to/config.file -y
。我想在一个单独的test.py
文件中编写一个简单的测试:执行脚本,传递提到的参数并获取它的所有输出。我传递了一个缺少某些东西的准备好的配置文件,因此run.py
它将中断并使用以下命令准确记录此错误logging.error
:“xyz 在配置文件中丢失!” (见下面的例子)。我会从中得到几句话print()
,然后logging
实例启动并从那里开始处理。我如何获得它的输出以便我可以检查它?随意重写这个,因为我还在学习,请多多包涵。
简化示例:
run.py
import logging
def run(args):
< args.config = /path/to/config.file >
cnfg = Config(args.config)
cnfg.logger.info("Let's start with the rest of the code!") # This is NOT in 'output' of the unittest
< code >
if __name__ == "__main__":
print("Welcome! Starting execution.") # This is in 'output' of the unittest
< code to parse arguments 'args' >
run(args)
Config.py
import logging
class Config:
def __init__(self):
print("Creating logging instance, hold on ...") # This is in 'output' of the unittest
logger = logging.getLogger(__name__)
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
logger.info("Logging activated, let's go!") # This is NOT in 'output' of the unittest
self.logger = logger
if xyz not in config:
self.logger.error("xyz was missing in Config file!") # This is NOT in 'output' of the unittest
exit(1)
test.py
import unittest
from unittest.mock import patch
class TestConfigs(unittest.TestCase):
def test_xyz(self):
with patch('sys.stdout', new=StringIO()) as capture:
with self.assertRaises(SystemExit) as cm:
run("/p/to/f/missing/xyz/f", "", False, True)
output = capture.getvalue().strip()
self.assertEqual(cm.exception.code, 1)
# Following is working, because the print messages are in output
self.assertTrue("Welcome! Starting execution." in output)
# Following is NOT working, because the logging messages are not in output
self.assertTrue("xyz was missing in Config file!" in output)
if __name__ == "__main__":
unittest.main()
解决方案
我会像这样重组run.py:
import logging
def main():
print("Welcome! Starting execution.")
Etc etc
if __name__ == "__main__":
main()
然后,您可以在单元测试中调用函数 run.main() 而不是分叉子进程。
from io import StringIO
from unittest.mock import patch
import sys
import run
class etc etc
def test_run etc etc:
with patch('sys.stdout', new=StringIO()) as capture:
sys.argv = [‘run.py’, ‘-flag’, ‘-flag’, ‘-flag’]
run.main()
output = capture.getvalue().strip()
assert output == <whatever you expect it to be>
如果您不熟悉单元测试,那么您之前可能没有见过模拟。实际上,我正在用假的标准输出替换标准输出,以捕获发送到那里的所有内容,以便稍后将其拉出到变量输出中。
事实上,围绕 sys.argv 的第二个补丁会更好,因为我在这里所做的,对真实 argv 的分配,实际上会改变它,这将影响同一文件中的后续测试。
推荐阅读
- sass - Angular 11 指令如何动态更改从 scss 变量读取的颜色代码
- windows - vagrant 在 WSL2 中不起作用 字符设备所需的标头 linux-headers-standard
- reactjs - 使用 react-query 和 axios 测试 React 组件中的错误的问题。使用 React 测试库、Jest、msw 进行测试
- mysql - 比较简单的查询速度极慢。我究竟做错了什么?
- angular - 为什么角素数 p-carousel 不能处理静态数据?
- python - pyinstaller 无法为 Django 生成可执行文件
- node.js - 为什么我不能使用其 ID 读取文档
- sql - 历史数据中的学生 Gradejump 与他们进行gradejump 的具体日期
- openssl - 在覆盆子 3 上安装 relasense D435
- r - 如何在 R data.frame 中禁用部分列名匹配?