[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