[TIP] mock a base class and imported modules?
Michael Foord
fuzzyman at voidspace.org.uk
Fri Mar 9 16:37:19 PST 2012
On 9 Mar 2012, at 15:08, Michael Foord wrote:
>
> 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.
Why can't you just patch MyClass.emit? If it doesn't exist you can put it in place (inherited from base class) with:
with patch('module.MyClass.emit', create=True): as mock_emit:
...
Michael
>> 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
>
>
>
>
>
>
> _______________________________________________
> 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