Pytest:python 中的模拟/猴子修补内置 input() 和 print() 函数
Pytest: mocking / monkey patching builtin input() and print() functions in python
我如何使用 Pytest 猴子修补内置 input
和 print
函数,以便在重构之前捕获其他人代码的输出并使用 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.in
和 mytest.out
文件的目录,并使用 @pytest.mark.parametrize(...)
将输入传递给 pytest
。
但我不知道如何修补这个 class 中笨拙的 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 ...
你能帮忙吗?
非常感谢
在等待回复的过程中,我自己想到了以下内容。我认为理想的答案是我按照@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
嘿,我想这对你来说已经太晚了,但对于其他人问自己如何 monkeypatch input(),我是这样做的:
monkeypatch.setattr(builtins, 'input', lambda *args, **kwargs: 'Yes, I like monkeypatching')
因此,我将重构您在自己的答案中发布的代码并将其更新为(假设该命令是可调用的,因为您将其指定为 side_effect):
@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
我如何使用 Pytest 猴子修补内置 input
和 print
函数,以便在重构之前捕获其他人代码的输出并使用 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.in
和 mytest.out
文件的目录,并使用 @pytest.mark.parametrize(...)
将输入传递给 pytest
。
但我不知道如何修补这个 class 中笨拙的 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 ...
你能帮忙吗?
非常感谢
在等待回复的过程中,我自己想到了以下内容。我认为理想的答案是我按照@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
嘿,我想这对你来说已经太晚了,但对于其他人问自己如何 monkeypatch input(),我是这样做的:
monkeypatch.setattr(builtins, 'input', lambda *args, **kwargs: 'Yes, I like monkeypatching')
因此,我将重构您在自己的答案中发布的代码并将其更新为(假设该命令是可调用的,因为您将其指定为 side_effect):
@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