[TIP] mock can't address a class by class name

Carl Meyer carl at oddbird.net
Wed Dec 12 14:49:47 PST 2012


Hi Yang,

On 12/12/2012 03:08 PM, Yang wrote:
> if I have mymodule.py:
> 
> class MyClass: def run(): return 1
> 
> 
> 
> then I try to mock it in test:
> 
> 
> with patch('mymodule.MyClass') as mock: instance = mock.return_value
> 
> mock.run.return_value =2
> 
> 
> this works fine. but if in my test code, I import the MyClass first:
> 
> from mymodule import MyClass
> 
> with patch('MyClass') as mock: ......
> 
> it fails to find 'MyClass'

Correct; patch's name lookups must be fully-qualified module paths,
they are not relative to the current module. If you want to patch some
methods or attributes of an object that you actually have a reference to
in your test module, you can use patch.object
(http://www.voidspace.org.uk/python/mock/patch.html#patch-object).

> even more serious is that if I refer to the mock class with full
> name mymodule.Myclass in the patch() line, but the production code
> refers to it as simply Myclass after importing it first, the mock
> does not take effect,  so I have to modify production code to mock it
> out. this completely does not work for real testing cases.

When you use mock.patch, you are not magically replacing some object
throughout your codebase. Rather, you are overriding one particular
_name_ in one particular module namespace to point to your mock object
rather than to the original object.

The implication of this is that you must patch where the object is
looked up by the system under test, not where it is defined. In other
words, if you are testing "targetmodule" which does "from mymodule
import MyClass", you need to patch("targetmodule.MyClass") not
patch("mymodule.MyClass").

For more details, read the documentation:
http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

Carl



More information about the testing-in-python mailing list