266

我正在使用 pythons mock.patch 并想更改每个调用的返回值。这里需要注意的是:被修补的函数没有输入,所以我不能根据输入更改返回值。

这是我的代码供参考。

def get_boolean_response():
    response = io.prompt('y/n').lower()
    while response not in ('y', 'n', 'yes', 'no'):
        io.echo('Not a valid input. Try again'])
        response = io.prompt('y/n').lower()

    return response in ('y', 'yes')

我的测试代码:

@mock.patch('io')
def test_get_boolean_response(self, mock_io):
    #setup
    mock_io.prompt.return_value = ['x','y']
    result = operations.get_boolean_response()

    #test
    self.assertTrue(result)
    self.assertEqual(mock_io.prompt.call_count, 2)

io.prompt只是“输入”的平台独立(python 2和3)版本。所以最终我试图模拟用户的输入。我曾尝试使用列表作为返回值,但这并不能正常工作。

你可以看到,如果返回值是无效的,我会在这里得到一个无限循环。所以我需要一种方法来最终改变返回值,这样我的测试才能真正完成。

(回答这个问题的另一种可能方法是解释我如何在单元测试中模仿用户输入)


不是这个问题的重复,主要是因为我没有能力改变输入。

关于这个问题的答案的评论之一是相同的,但没有提供答案/评论。

4

3 回答 3

448

您可以将一个可迭代对象分配给side_effect,并且模拟将在每次调用时返回序列中的下一个值:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

引用Mock()文档

如果side_effect是一个可迭代对象,那么对模拟的每次调用都将返回可迭代对象的下一个值。

于 2014-07-22T20:34:16.490 回答
1

对于多个返回值,我们也可以在补丁初始化期间使用side_effect并将 iterable 传递给它

示例.py

def hello_world():
    pass

test_sample.py

from unittest.mock import patch
from sample import hello_world

@patch('sample.hello_world', side_effect=[{'a': 1, 'b': 2}, {'a': 4, 'b': 5}])
def test_first_test(self, hello_world_patched):
    assert hello_world() == {'a': 1, 'b': 2}
    assert hello_world() == {'a': 4, 'b': 5}
    assert hello_world_patched.call_count == 2
于 2021-09-12T20:30:19.623 回答
-5

您还可以使用 patch 获取多个返回值:

@patch('Function_to_be_patched', return_value=['a', 'b', 'c'])

请记住,如果您对一个方法使用多个补丁,那么它的顺序将如下所示:

@patch('a')
@patch('b')
def test(mock_b, mock_a);
    pass

正如您在此处看到的,它将被还原。首先提到的补丁将位于最后一个位置。

于 2021-03-29T09:58:51.433 回答