Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock python function with multiple return values

I have a python function that returns multiples values. My function:

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)

I want to give my own values to the returned values from FunctionIWantToTest. So, I'm trying to test the 2nd function with nosetest, but I don't know how to mock the return of myExampleFunction.

I tried this:

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

But it doesn't work. When I launch nosetests I read this message:

ValueError: too many values to unpack

Any idea? I use python 2.7.3

like image 440
myg Avatar asked Mar 03 '16 13:03

myg


People also ask

How do you return multiple things from a function in Python?

In Python, you can return multiple values by simply return them separated by commas. In Python, comma-separated values are considered tuples without parentheses, except where required by syntax. For this reason, the function in the above example returns a tuple with each value as an element.

What is the difference between mock and MagicMock?

So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

How do you mock a function in Python?

How do we mock in Python? Mocking in Python is done by using patch to hijack an API function or object creation call. When patch intercepts a call, it returns a MagicMock object by default. By setting properties on the MagicMock object, you can mock the API call to return any value you want or raise an Exception .

What is Side_effect in mock Python?

side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.


2 Answers

Just wanted to share how to get this to work with side_effect. I put together a simplified version to showcase how to use side_effect for your use case.

side_effect behaves differently than return_value, where when you provide a side_effect with a list with entries, what you are stating actually is that, each time your mocked method is called it will return each item in the list as its return value. This is actually why you are getting ValueError: too many values to unpack (expected 3), because by doing this:

[1, 2, 3]

You are saying, for each call to my mocked method, return 1, then the next time I call the method, return 2, then return 3.

With that in mind, if you set up your side_effect, like this:

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

What you are now saying, is that, for when you call side_effect, the first item in the list is what will be returned. Which, in effect is:

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

Alternatively, you can do this:

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

Which mimics out the method you are testing by taking two args and returning the three values it should return.

So, with this in mind, your test can be structured as:

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()
like image 75
idjaw Avatar answered Oct 18 '22 20:10

idjaw


You need to set the return_value of the mock, not side_effect.

You can do this when you instantiate it:

c.myExampleFunction = Mock(return_value=["myName", 100, 200])
like image 36
Daniel Roseman Avatar answered Oct 18 '22 19:10

Daniel Roseman