pytest 猴子补丁终端大小



我在pytest中玩猴子补丁夹具,试图模拟终端窗口的当前大小。

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 widthn'
def mock_size():
return '10 20n'
monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)
assert get_terminal_size() == '10 20n'

当我运行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 widthn'
def mock_size():
return '10 20n'
monkeypatch.setattr(os.popen('stty size', 'r'), 'read', mock_size)
>       assert get_terminal_size() == '10 20n'
E       AssertionError: assert '' == '10 20n'
E         + 10 20
test_monkeypatch.py:15: AssertionError

所以看起来它没有设置mock_size。我尝试遵循pytest文档中的模式

关于让它工作的任何建议?

提前感谢!

更新:正如Kent Shikama在下面的答案中指出的那样,对于我尝试捕获输出的方式,我需要使用-s标志来关闭pytest捕获。

但是随着对popen用法的进一步研究,特别是从使用os.popen到子进程的迁移。Popen,看到这里,以及这篇关于"如何伪造Popen"的S.O.帖子的一些帮助,我想出了一个解决方案。

这是新的设置:

# 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 widthn'
def mock_terminal_size(cmd, **kwargs):
return '10 20n'
monkeypatch.setattr(m_patch, 'Popen' , mock_terminal_size)
assert m_patch.get_terminal_size() == '10 20n'

起初对我来说并不明显的事实是,mock_terminal_size函数将处理它正在模拟的 Popen 方法的参数,因此它必须接受 Popen 在原始函数中使用的参数。我本可以专门将 shell 参数添加到mock_terminal_size,但由于 Popen 接受一长串 kwarg,我有点模棱两可。

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

首先,您需要使用-s标志运行 pytest,否则 stty 将被捕获。然后你应该得到你可能期望的断言错误,如下所示:

>       assert get_terminal_size() == '10 20n'
E       AssertionError: assert '24 80n' == '10 20n'
E         - 24 80
E         + 10 20

听起来你想模拟流上的读取方法,以便它始终运行"10 20"。通常你会做这样的事情

from io import TextIOWrapper
monkeypatch.setattr(TextIOWrapper, 'read', mock_size)

但不幸的是,你不能模拟内置对象。你可以尝试一些类似禁果的东西来克服这个问题,但感觉你可能想改变你的方法。

最新更新