[TIP] Mocking properties on an instance
fuzzyman at voidspace.org.uk
Sun Sep 4 15:29:09 PDT 2011
On 04/09/2011 23:04, Julian Berman wrote:
> On Sep 4, 2011, at 11:56 AM, Michael Foord wrote:
>> Interesting. I've long known that the one thing you can't do with patch is patch out a property, or other property-like descriptor, on an *instance*. This isn't normally a problem because you can patch on the class instead - but of course that doesn't work where you have multiple instances to patch.
>> I haven't dealt with this previously as you're the first person to report it as a problem in practise rather than just in theory. :-)
>> Your solution is fine, so long as there is no property setter (the AttributeError must be raised when attempting to put the patch in place in order to detect the problem). So I don't think this is a *general* solution.
>> A general solution would involve replacing the descriptor on the class with something that knows what instances have been patched and delegates to the real descriptor for any other instance.
>> I've created an issue to track the problem. It's too late to get a fix into 0.8, but I'll consider the issue for the next release:
> Cool, yeah I didn't actually mean for that to be the actual general implementation ;). Thank you for considering it.
> Also, I think I see you guys have a skipped test in tests/test_patch.py that covers this issue already so I see you had it in mind.
> Perhaps on a slightly different note:
> I found myself in this same project, needing to check that a bunch of events fired. So, I mocked out my event handler.. But obviously, all I can be sure of (and all I really care to test) is that all the events that should have fired did, and that they appear in the order I expect. I make no assumptions about other events that may fire in between.
> So, checking call_args_list meant writing a function that checked for a non-contiguous ordered subset of the calls, instead of just regularly checking containment. Feature creep sucks I know, and it's not as though it's more than 3-5 lines to write, but while I'm at it, that's not something that would be of wider benefit would it?
Time machine to the rescue. Using mock 0.8 beta 3:
>>> from mock import MagicMock, call
>>> m = MagicMock(return_value=None)
>>> m(1, 2, 3)
>>> m(4, 5, 6)
>>> m(7, 8, 9)
>>> m(10, 11, 12)
>>> m.assert_has_calls([call(1, 2, 3), call(10, 11, 12), call(7, 8,
> (P.S. I really do wish python had a sortedset and frozendict type already but that is a different discussion :/ )
(There was a proposal to make sets sorted by default. I'm not sure what
has happened to that though.)
All the best,
May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing http://www.sqlite.org/different.html
More information about the testing-in-python