[TIP] mock a base class and imported modules?
fuzzyman at voidspace.org.uk
Fri Mar 9 15:08:09 PST 2012
On 9 Mar 2012, at 11:44, skip at pobox.com wrote:
> I have a class to test which subclasses gobject.GObject:
> I don't really need much of the base class for my testing except the ability
> to emit signals. Is there some way to mock the base class before importing
> the module containing my class? Skeletal example:
> import gobject
> import another_module
> class MyClass(gobject.GObject):
> def __init__(self, ...)
> def some_method(self, ...);
> x = another_module.SomeClass()
> def another_method(self, ...):
> self.emit("mysignal", ...)
> The emit method comes from the base class.
> Reading the documentation for the patch decorator it's not clear to me that
> mock will get a shot at replacing the gobject.GObject reference before
> MyClass is defined. I assume (without empirical proof at this point) that I
> will be able to use patch to stub out another_module.SomeClass though, since
> it isn't used until I have a MyClass instance.
> Any suggestions appreciated. (Mock usage is still very new to me. You will
> probably have to use very small words and speak slowly.)
You're correct that in general you can't use mock / patch to replace base classes for a class that has already been defined (imported). For another_module.SomeClass you can patch it because the lookup is done at runtime rather than import time.
Although it is possible to replace Class.__bases__ it can only be with a tuple of real classes, and not a mock object, and there are several other restrictions that make it hard for this to be a useful approach.
You *could* mock gobject.GObject before your code is imported by putting a mock gobject into sys.modules using patch.dict:
mock_gobject = MagicMock()
mock_gobject.GObject.__bases__ = (object,)
with patch.dict('sys.modules', gobject=mock_gobject):
This will work because although you can't patch Class.__bases__ to contain a mock, you can subclass a mock object if it has a __bases__ attribute (!).
>>> from mock import MagicMock
>>> m = MagicMock(name='klass')
>>> m.__bases__ = (object,)
>>> class Foo(m): pass
<MagicMock spec='str' id='4300695632'>
> Skip Montanaro - skip at pobox.com - http://www.smontanaro.net/
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
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
More information about the testing-in-python