[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'>


> 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


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 mailing list