【问题标题】:pytest monkeypatch terminal sizepytest monkeypatch 终端大小
【发布时间】:2020-02-18 01:02:12
【问题描述】:

我正在使用 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 在下面的答案中指出的那样,对于我尝试捕获输出的方式,我需要使用 -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 接受一长串 kwarg,所以我有点模棱两可。

现在,当我运行 pytest 并且不需要 -s 标志时,这会通过,因为我不再尝试捕获输出,而是模拟 Popen 方法的执行。

【问题讨论】:

    标签: python python-3.x pytest


    【解决方案1】:

    首先,您需要使用 -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 之类的方法来克服这个问题,但感觉你可能想改变你的方法。

    【讨论】:

    • 感谢您的意见。我考虑改变我的方法并用我的发现更新了帖子。您似乎可以模拟内置对象,但首选方法是模拟特定于您正在测试的函数的对象以本地化范围,即monkeypatch(func.Object, 'method', mock_func
    猜你喜欢
    • 2017-11-23
    • 2020-12-28
    • 1970-01-01
    • 2018-07-27
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多