为什么 monkeypatch 无法识别构造函数中的赋值?

Why does monkeypatch not recognize an assignment value in the constructor?

我正在练习 TDD,我对此还很陌生。在我的测试用例中,我想从 stdin 读取并检查输出是否与输入匹配。

对于 stdin 我想使用模拟对象。因此,我使用 monkeypatch.setattr('sys.stdin', StringIO(string))stdin 替换为 StringIO,因为两者都有 read().

方法
# XPath.py
import sys
from io import StringIO

class XPath:
    def __init__(self):
        self.stdin = sys.stdin

    def readStdin(self):
        return self.stdin.read()
# TestXPath.py
import pytest
from XPath import XPath
from io import StringIO

def test_CanReadFromStdin(monkeypatch):
    xpath = XPath()
    string = "<a></a>\n"
    monkeypatch.setattr('sys.stdin', StringIO(string))
    assert xpath.readStdin() == string

然而,这失败了

FAILED                               [100%]
TestXPath.py:4 (test_CanReadFromStdin)
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f2dafc5ec90>

    def test_CanReadFromStdin(monkeypatch):
        xpath = XPath()
        string = "<a></a>\n"
        monkeypatch.setattr('sys.stdin', StringIO(string))
>       assert xpath.readStdin() == string

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
XPath.py:9: in readStdin
    return self.stdin.read()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

pytest 在没有任何标志的情况下被调用。添加 -s 导致永无止境的循环。有趣的是,当我在省略构造函数的同时将 XPath.py 中的行更改为:

    def readStdin(self):
        return sys.stdin.read()

测试运行成功。

为什么构造函数中的赋值不起作用?

我想到了这个解决方案。我正在使用图书馆的 Mock()。然后我删除了构造函数中的stdin赋值。

#XPath.py
import sys
class XPath:
    def __init__(self, stream):
        self.stream = stream
        pass

    def readStdin(self):
        return self.stream.read()


# test_file.py
import pytest
from XPath import XPath
from io import StringIO

def test_CanReadFromStdin(monkeypatch):
    string = "<a></a>\n"
    from unittest.mock import Mock
    mock_stdin = Mock()
    mock_stdin.readline = Mock(StringIO(string))
    monkeypatch.setattr('sys.stdin', StringIO(string))
    import sys
    xpath = XPath(sys.stdin)
    assert xpath.readStdin() == string

更新: 为了演示目的,我再次将流 (stdin) 包含到构造函数中。这样我就可以编写第二个方法并传递一个文件描述符。