[TIP] mock a base class and imported modules?
Michael Foord
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:
>
> http://www.pygtk.org/docs/pygobject/class-gobject.html
>
> 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, ...)
> gobject.GObject.__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):
import mycode
...
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
...
>>> Foo
<MagicMock spec='str' id='4300695632'>
Michael
>
> Thx,
>
> --
> Skip Montanaro - skip at pobox.com - http://www.smontanaro.net/
>
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python
>
--
http://www.voidspace.org.uk/
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
mailing list