Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python mock return of a getattr() call

Edit: I might be falling the XY problem trap here. Here's what I really want to know.

I have the following function:

def foo():
  bar = funcToGetBar()
  return bar.getattr("some_attr", None)

In my test, I try to do:

mocked_bar = MagicMock()
expected_return_val = [obj1, obj2, ...]
funcToGetBar.return_value = mocked_bar  # funcToGetBar is patched

def testGetBar(self):
  assertEqual(expected_return_val, foo())

Now what I want to do is to provide the expected_return_val onto the some_attr attribute on the bar object.

I have tried using PropertyMock:

type(mocked_bar).getattr = PropertyMock(return_value=expected_return_value)

Running my test I get the error:

TypeError: 'list' object is not callable

If the return_value is set to a scalar (not a list), the result of the getattr call in the real function is a mock, and not the scalar I provided.

Also, I'm worried about mocking out the getattr method, since it is a common method that will probably be used elsewhere in my function. How can I set a list on an attribute of my mock object under test?

like image 561
ericso Avatar asked Apr 21 '16 22:04

ericso


People also ask

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.


1 Answers

Per the documentation, Mock's return_value isn't iterable. To get an iterable return_value, use side_effect.

mocked_bar = MagicMock()
mocked_bar.side_effect = [obj1, obj2, ...]

edit: Documentation is located at https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock

specifically:

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.

like image 176
ianlaughlin Avatar answered Sep 19 '22 14:09

ianlaughlin