Python 模拟多个返回值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24897145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 05:26:00  来源:igfitidea点击:

Python mock multiple return values

pythonunit-testingmockingpython-mock

提问by Nick Humrich

I am using pythons mock.patch and would like to change the return value for each call. Here is the caveat: the function being patched has no inputs, so I can not change the return value based on the input.

我正在使用 python mock.patch 并希望更改每次调用的返回值。这是警告:被修补的函数没有输入,所以我不能根据输入更改返回值。

Here is my code for reference.

这是我的代码供参考。

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')

My Test code:

我的测试代码:

@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.promptis just a platform independent (python 2 and 3) version of "input". So ultimately I am trying to mock out the users input. I have tried using a list for the return value, but that doesn't seam to work.

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

You can see that if the return value is something invalid, I will just get an infinite loop here. So I need a way to eventually change the return value, so that my test actually finishes.

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

(another possible way to answer this question could be to explain how I could mimic user input in a unit-test)

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



Not a dup of this questionmainly because I do not have the ability to vary the inputs.

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

One of the comments of the Answer on this questionis along the same lines, but no answer/comment has been provided.

答案对此问题的评论之一与相同,但未提供任何答案/评论。

采纳答案by Martijn Pieters

You can assign an iterableto side_effect, and the mock will return the next value in the sequence each time it is called:

你可以指定一个迭代side_effect,并模拟将序列中的每个被调用时,返回的下一个值:

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

Quoting the Mock()documentation:

引用Mock()文档

If side_effectis an iterable then each call to the mock will return the next value from the iterable.

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

As an aside, the test response is not 'y' or 'n' or 'yes' or 'no'will notwork; you are asking if the expression (response is not 'y')is true, or 'y'is true (always the case, a non-empty string is always true), etc. The various expressions on either side of oroperators are independent. See How do I test one variable against multiple values?

顺便说一句,该测试response is not 'y' or 'n' or 'yes' or 'no'无法正常工作; 您是在询问表达式(response is not 'y')是否为真,还是'y'为真(总是如此,非空字符串始终为真)等。or运算符两侧的各种表达式是独立的。请参阅如何针对多个值测试一个变量?

You should alsonot use isto test against a string. The CPython interpreter mayreuse string objects under certain circumstances, but this is not behaviour you should count on.

你应该不会使用is,以测试对一个字符串。CPython 解释器可能会在某些情况下重用字符串对象,但这不是您应该指望的行为。

As such, use:

因此,请使用:

response not in ('y', 'n', 'yes', 'no')

instead; this will use equalitytests (==) to determine if responsereferences a string with the same contents (value).

反而; 这将使用相等测试 ( ==) 来确定是否response引用了具有相同内容(值)的字符串。

The same applies to response == 'y' or 'yes'; use response in ('y', 'yes')instead.

这同样适用于response == 'y' or 'yes'; 使用response in ('y', 'yes')来代替。