模拟python函数具有多个返回值

时间:2016-03-03 13:53:32

标签: python mocking nose

我有一个返回多个值的python函数。我的功能:

def myExampleFunction(a,b)
    # here is my code
    return name, number1, number2


def FunctionIWantToTest(self):
    # here is my code
    myName, myNumber1, myNumber2 = self.myExampleFunction(a,b)

我想将自己的值赋予FunctionIWantToTest返回的值。所以,我试图用nosetest测试第二个函数,但我不知道如何模拟myExampleFunction的返回。

我试过了:

def test_mytest(self):
    [...]
    c.myExampleFunction = Mock()
    c.myExampleFunction.side_effect = ["myName", 100, 200]
    [...]

但它不起作用。当我启动nosetests时,我读到了这条消息:

ValueError: too many values to unpack

有什么想法吗?我使用python 2.7.3

2 个答案:

答案 0 :(得分:9)

您需要设置模拟的side_effect,而不是c.myExampleFunction = Mock(return_value=["myName", 100, 200])

您可以在实例化时执行此操作:

SELECT DISTINCT p.ID
FROM  posts p
LEFT JOIN  postmeta m ON p.ID = m.post_id
WHERE p.post_type = 'babysitter'
AND p.post_status = 'publish'
AND m.meta_key = 'distance' 
AND ( m.meta_value > (SELECT meta_value 
                       FROM postmeta 
                       WHERE meta_key = 'radius' ))  

答案 1 :(得分:4)

只想分享如何使其与side_effect一起使用。我整理了一个简化版本,以展示如何将side_effect用于您的用例。

side_effect的行为与return_value不同,当你向side_effect提供带有条目的列表时,你实际上说的是,每次调用模拟方法时,它都将返回每个项目列表作为其返回值。这实际上就是为什么你得到 ValueError:太多的值来解包(预期3),因为这样做:

[1, 2, 3]

你说,对于我的模拟方法的每次调用,返回1,然后下次调用方法时,返回2,然后返回3.

考虑到这一点,如果您设置side_effect,就像这样:

[('stuff1', 'stuff2', 'stuff3')]

您现在所说的是,当您调用side_effect时,列表中的第一项是将返回的内容。其中,实际上是:

('stuff1', 'stuff2', 'stuff3')

或者,你可以这样做:

my_test_foo.side_effect = lambda x, y: (1, 2, 3)

通过取两个args并返回它应该返回的三个值来模拟你正在测试的方法。

因此,考虑到这一点,您的测试可以结构化为:

import unittest
from unittest.mock import Mock

from mock import patch
from stuff import FunctionIWantToTest


class MyTest(unittest.TestCase):

    @patch('stuff.myExampleFunction', return_value=Mock())
    def test_mytest(self, m_example_function):
        m_example_function.side_effect = [("stuff1", 100, 200)]
        # m_example_function.side_effect = lambda x, y: ("stuff1", 100, 200)

        a, b, c = FunctionIWantToTest()

if __name__ == '__main__':
    unittest.main()