【问题标题】:Pytest: mocking / monkey patching builtin input() and print() functions in pythonPytest:在 python 中模拟/猴子修补内置 input() 和 print() 函数
【发布时间】:2018-05-09 08:24:22
【问题描述】:

如何使用 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 ...

你能帮忙吗?

非常感谢

【问题讨论】:

    标签: python mocking pytest monkeypatching


    【解决方案1】:

    在等待回复时,我自己想出了以下内容。我认为理想的答案将是我按照@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
    

    【讨论】:

    【解决方案2】:

    嘿,我想这对你来说已经太晚了,但是对于其他人问自己如何修改 input(),我是这样做的:

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

    因此,我会将您在自己的答案中发布的代码重构为(假设命令是可调用的,因为您将其指定为副作用):

    @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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2013-04-13
      • 2011-01-23
      相关资源
      最近更新 更多