Reputation: 384
When mocking a class object I can't access it's attributes. I've read a lot of documentation but I'm new to mocking and don't see the problem with this code. I expect x and y to return the same value 1e-15
class test_user_data:
scale = 1e-15
class test_signal(unittest.TestCase):
@patch('xx.user_data', autospec=test_user_data, spec_set=True)
def test_data(self, mock_user_data):
x = xx.user_data()
y = test_user_data()
print(x.scale)
print(y.scale)
but I get
<NonCallableMagicMock name='user_data().timescale' spec_set='float' id='47213638195072'>
1e-15
Upvotes: 3
Views: 6226
Reputation: 3828
autospec
and spec'ing in general is used to define an API. When using a Mock
, you can pretty much call or access any attribute on it and it'll just let you. It will return another mock object though.
See something like this:
>>> my_mock = Mock()
>>> my_mock.stuff
<Mock name='mock.stuff' id='139870989908344'>
>>> my_mock.junk()
<Mock name='mock.junk()' id='139870987197912'>
If I define a spec, it says you can't access things that don't actually exist on the real class. Like so:
>>> my_mock = Mock(spec=xx.user_data)
>>> my_mock.stuff
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 574, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'stuff'
>>> my_mock.scale
<Mock name='mock.scale' id='139871128095264'>
So the above shows you can't access an attribute on the Mock that isn't defined in the actual user_data
class because I've used spec.
That explains how autospec works, but what you actually want is the return_value
arg. Go ahead and add it to your patch decorator and you should be all set. It should look like this:
@patch('xx.user_data', autospec=test_user_data, spec_set=True, return_value=test_user_data)
Upvotes: 1