我正在 pytest 中使用 Monkeypatch 固定装置,试图模拟终端窗口的当前大小。
import os
import pytest
def get_terminal_size():
terminal_size = os.popen('stty size', 'r').read()
return terminal_size
def test_get_terminal_size(monkeypatch):
# The get_terminal_size() function will return a string 'height width\n'
def mock_size():
return '10 20\n'
monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)
assert get_terminal_size() == '10 20\n'
当我运行 pytest 时,出现断言错误:
__________________________________________________________________ test_get_terminal_size __________________________________________________________________
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f5bf1ec0cf8>
def test_get_terminal_size(monkeypatch):
# The get_terminal_size() function will return a string 'height width\n'
def mock_size():
return '10 20\n'
monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)
> assert get_terminal_size() == '10 20\n'
E AssertionError: assert '' == '10 20\n'
E + 10 20
test_monkeypatch.py:15: AssertionError
所以看起来它没有设置mock_size。我尝试遵循 pytest documentation 中的模式
关于让它发挥作用有什么建议吗?
提前致谢!
更新: 正如 Kent Shikama 在下面的答案中指出的那样,对于我 try catch 输出的方式,我需要使用 -s 标志来关闭 pytest 捕获。
但随着对 popen 用法的进一步研究,特别是从使用 os.popen 迁移到 subprocess.Popen,请参阅 here ,以及来自此的一些帮助 S.O. post在“如何伪造 Popen”中,我想出了一个解决方案。
这是新设置:
# \mokeypatch_popen.py
from subprocess import Popen
def get_terminal_size():
terminal_size = Popen('stty size', shell=True)
return terminal_size
测试函数:
# \test_monkeypatch.py
import pytest
import monkeypatch_popen
def test_get_terminal_size(monkeypatch):
# The get_terminal_size() function will return a string 'height width\n'
def mock_terminal_size(cmd, **kwargs):
return '10 20\n'
monkeypatch.setattr(m_patch, 'Popen' , mock_terminal_size)
assert m_patch.get_terminal_size() == '10 20\n'
一开始对我来说并不明显的是,mock_terminal_size 函数将处理它正在模拟的 Popen 方法的参数,因此它必须接受 Popen 在原始函数中使用的参数。我本来可以专门将 shell 参数添加到mock_terminal_size,但由于 Popen 接受一长串 kwargs,所以我有点模糊。
现在,当我运行 pytest 时,这个问题就过去了,并且 -s 标志不是必需的,因为我不再 try catch 输出,而是模拟 Popen 方法的执行。
最佳答案
首先,您需要使用 -s
标志运行 pytest,否则 stty 将被捕获。然后你应该得到你可能期望的断言错误,如下所示:
> assert get_terminal_size() == '10 20\n'
E AssertionError: assert '24 80\n' == '10 20\n'
E - 24 80
E + 10 20
听起来您想模拟流上的读取方法,使其始终运行“10 20”。通常你会做类似的事情
from io import TextIOWrapper
monkeypatch.setattr(TextIOWrapper, 'read', mock_size)
但不幸的是你不能模拟内置对象。您可以尝试类似 forbiddenfruit来克服这个问题,但感觉你可能想要改变你的方法。
关于python - pytest Monkeypatch 终端大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60272369/