Pytest:mock/patch sys.stdin 在程序中使用 python 线程

Pytest: mock/patch sys.stdin in program using threading with python

我已经获得了一些需要在重构前测试的代码。它使用深度递归,因此设置了新的限制,然后在新线程中自行运行:

sys.setrecursionlimit(10**6)
threading.stack_size(2**27)
...
threading.Thread(target=main).start()

该代码严重依赖于 sys.stdinsys.stdout,例如

class SpamClass:
    def read(self):
        self.n = int(sys.stdin.readline())
        ...
        for i in range(self.n):
            [a, b, c] = map(int, sys.stdin.readline().split())
    ...
    def write(self)
        print(" ".join(str(x) for x in spam()))

为了测试代码,我需要传入一系列输入文件的内容,并将结果与​​一些相应的示例输出文件的内容进行比较。

到目前为止,我已经尝试了三四种不同类型的模拟和修补,但都没有成功。我的其他测试都是为 pytest 编写的,因此必须使用其他东西真的很麻烦。

我已经尝试用 StringIO 修补 module.sys.stdin,这似乎不起作用,因为 pytest 的 capsyssys.stdin 设置为 null,因此尽管抛出错误补丁。

我也尝试过使用 pytest 的 monkeypatch fixture 将 module.SpamClss.read 方法替换为测试中定义的函数,但我认为这会产生分段错误,原因是线程退出在测试之前(或......?)。

'pytest test_spam.py' terminated by signal SIGBUS (Misaligned address error)

关于如何正确执行此操作的任何建议?非常感谢。

好吧,我仍然不知道问题出在哪里,也不知道我这样做是否正确,但目前它是有效的。我不确定线程​​方面是否正常工作,但其余部分似乎还不错。

@pytest.mark.parametrize("inputs, outputs", helpers.get_sample_tests('spampath'))
def test_tree_orders(capsys, inputs, outputs):
    """
    """
    with patch('module.sys.stdin', StringIO("".join(inputs))):
        module.threading.Thread(target=module.main()).start()

    captured = capsys.readouterr()

    assert "".join(outputs) == captured.out

对于任何其他感兴趣的人,它有助于将调试打印作为 print(spam, file=sys.stderr),然后您可以在测试中作为 captured.err 访问它,请参见。 captured.out 用于测试。