Pytest:如何在Python中mock / monkey patch内置的input()和print()函数

3

如何使用 Pytest 对内置的 inputprint 函数进行猴子补丁,以便在重构之前捕获其他人的代码输出并使用 pytest 进行测试?

例如,我已经获得了类似于以下代码的一些代码:

class QueryProcessor:
    def __init__(self ...):
        ...  

    def write_search_result(self, was_found):
        print('yes' if was_found else 'no')

    def read_query(self):
        return Query(input().split())

我不想从stdin读取数十个输入参数,也不想print输出。我想使用我编写的函数,这些函数可以筛选包含mytest.inmytest.out文件的目录,并使用@pytest.mark.parametrize(...)将输入传递给pytest
但是,我无法弄清楚如何修补该类中笨拙的read...write...函数。
我怀疑应该这样做:
@yptest.mark.parametrize("inputs…, expected outputs…", data_reading_func())
def test_QueryProcessor(monkeypatch, inputs…, expected outputs…):
   """Docstring
   """
   q = QueryProcessor()

   def my_replacement_read():
       ...
       return [...]

   def my_replacement_write():
       ...
       return [...]

   monkeypatch.???
   assert ...

您好,需要帮忙吗?

非常感谢。

2个回答

2

在等待回复时,我自己想出了以下内容。我认为理想的答案将是我所做的以@hoefling建议的方式实现-使用patch

@pytest.mark.parametrize("m, n, commands, expec", helpers.get_external_inputs_outputs('spampath', helpers.read_spam_input_output))
def test_QueryProcessor(monkeypatch, m, n, commands, expec):

    def mock_process_queries(cls):
        for cmd in commands:
            cls.process_query(Query(cmd.split())) # also mocks read_query()

    def mock_write_search_result(cls, was_found):
        outputs.append('yes' if was_found else 'no')

    monkeypatch.setattr('test.QueryProcessor.process_queries', mock_process_queries)
    monkeypatch.setattr('test.QueryProcessor.write_search_result', mock_write_search_result)

    outputs = []

    proc = QueryProcessor(m)
    proc.process_queries()

    assert outputs == expec

更新:

@pytest.mark.parametrize("m, n, commands, expec",
                         helpers.get_external_inputs_outputs(
                             'spampath',
                             helpers.read_input_output))
def test_QueryProcessor_mockpatch(m, n, commands, expec):

    commands.insert(0,n)

    mock_stdout = io.StringIO()

    with patch('spammodule.input', side_effect=commands):
        with patch('sys.stdout', mock_stdout):
            proc = hash_chains.QueryProcessor(m)
            proc.process_queries()

    assert mock_stdout.getvalue().split('\n')[:-1] == expec

你从哪里获取补丁? - Andru
我假设 unittest.mock.patch - Steven

1

嘿,我猜现在可能已经太晚了,但对于其他想知道如何 monkeypatch input() 的人,我是这样做的:

monkeypatch.setattr(builtins, 'input', lambda *args, **kwargs: 'Yes, I like monkeypatching')

所以,我会重构你在自己的答案中发布的代码更新为以下内容(假设commands是可调用的,因为你将其指定为side_effect):

# don't forget the imports
import builtins
import io
import sys

@pytest.mark.parametrize("m, n, commands, expec",
    helpers.get_external_inputs_outputs('spampath',helpers.read_input_output))
def test_QueryProcessor_mockpatch(monkeypatch, m, n, commands, expec):

    commands.insert(0,n)

    mock_stdout = io.StringIO()
    monkeypatch.setattr(builtins, 'input', lambda description: commands())
    monkeypatch.setattr(sys, 'stdout', mock_stdout)

    proc = hash_chains.QueryProcessor(m)
    proc.process_queries()

    assert mock_stdout.getvalue().split('\n')[:-1] == expec

builtins从哪里导入? - LightCC
1
@LightCC import builtins - Eric M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接