Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper way to mock a subscriptable property that raises an exception when accessed in Python 2.7?

Tags:

python

mocking

Python 2.7.1, mock 1.0.1

I want to write a unit test that makes use of the functionality shown here, namely successfully raising an IndexError when an attempt is made to access a mock property with subscript syntax like so:

repo = MagicMock()
repo.heads = PropertyMock(side_effect=IndexError())
with self.assertRaises(IndexError):
    _ = repo.heads['nonexistant']

What is most pythonic way to do this? The code above doesn't raise an IndexError at all, but rather a TypeError indicating that PropertyMock is not subscriptable.

TypeError: 'PropertyMock' object is not subscriptable

I should note that the actual unit test doesn't look like this at all. The real unit test is attempting to assert certain behavior but cannot do so without mocking a class in the underlying third-party module, effectively replicating that underlying module's behavior when getitem is called on its Repo object which results in an IndexError being raised.

The context aside, am I being redundant by declaring repo as a MagicMock() object and then repo.heads as a PropertyMock object? I toiled over the mock documentation for awhile but there are no examples of this specific use case and I can't get this to work. I also tried using MagicMock(side_effect=IndexError()), to no avail.

It seems to me that one should be able to simply and easily facilitate this behavior in a mock and get on with their day. I trust this is possible but that I don't know how, which is why I'm asking this question.

What is the real solution?

like image 208
fenreer Avatar asked Apr 04 '14 20:04

fenreer


1 Answers

You can use MagicMock instead of PropertyMock for repo.heads. It should work for your example but I don't know if your actual tests depend on PropertyMock.

repo = MagicMock()
repo.heads.__getitem__.side_effect = IndexError
with self.assertRaises(IndexError):
    _ = repo.heads['nonexistant']

If you want it to raise IndexError on access to particular values you should assign a custom handler function to repo.heads.__getitem__.side_effect.

like image 67
and Avatar answered Oct 19 '22 11:10

and