python - pytest Monkeypatch 终端大小

标签 python python-3.x pytest

我正在 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/

相关文章:

python - 是 lambda :function() inside the same function considered recursive?

python - 如何获取对象属性的类型提示?

python-3.x - tkinter python 最大化窗口

python - 在 nose 或 pytest 中收集以编程方式生成的测试套件的好方法

python - 从 Python CGI 脚本中读取客户端的 header ?

python - 如何使用 Python 和 xarray 从变量满足 netCDF 数据集标准的位置提取坐标?

python - 如何使用 matplotlib 定义具有绝对值的颜色图

html - 如何设置 QTextDocument 边距和其他属性(setHTML,打印为 pdf)?

python - 我怎样才能使用 pytest 选项作为固定装置而不是重复自己?

python - 断言异常消息?