How to mock.patch a class imported in another module
Question:
I have a python class with such a module:
xy.py
from a.b import ClassA
class ClassB:
def method_1():
a = ClassA()
a.method2()
then I have ClassA defined as:
b.py
from c import ClassC
class ClassA:
def method2():
c = ClassC()
c.method3()
Now in this code, when writing test for xy.py I want to mock.patch ClassC, is there a way to achieve that in python?
obviously I tried:
mock.patch('a.b.ClassA.ClassC')
and
mock.patch('a.b.c.ClassC')
None of these worked.
Answers:
You need to patch where ClassC
is located so that’s ClassC
in b
:
mock.patch('b.ClassC')
Or, in other words, ClassC
is imported into module b
and so that’s the scope in which ClassC
needs to be patched.
Each time the method ClassA().method2()
is called, the method looks up ClassC
as a global, thus finding ClassC
in the a.b
module. You need to patch that location:
mock.patch('a.b.ClassC')
See the Where to patch section section.
patch() works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.
The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
In your case, the lookup location is a.b.ClassC
since you want to patch ClassC
used in ClassA
.
import mock
with mock.patch('a.b.ClassC') as class_c:
instance = class_c.return_value # instance returned by ClassC()
b = ClassB()
b.method1()
assert instance.method3.called == True
I have a python class with such a module:
xy.py
from a.b import ClassA
class ClassB:
def method_1():
a = ClassA()
a.method2()
then I have ClassA defined as:
b.py
from c import ClassC
class ClassA:
def method2():
c = ClassC()
c.method3()
Now in this code, when writing test for xy.py I want to mock.patch ClassC, is there a way to achieve that in python?
obviously I tried:
mock.patch('a.b.ClassA.ClassC')
and
mock.patch('a.b.c.ClassC')
None of these worked.
You need to patch where ClassC
is located so that’s ClassC
in b
:
mock.patch('b.ClassC')
Or, in other words, ClassC
is imported into module b
and so that’s the scope in which ClassC
needs to be patched.
Each time the method ClassA().method2()
is called, the method looks up ClassC
as a global, thus finding ClassC
in the a.b
module. You need to patch that location:
mock.patch('a.b.ClassC')
See the Where to patch section section.
patch() works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.
The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
In your case, the lookup location is a.b.ClassC
since you want to patch ClassC
used in ClassA
.
import mock
with mock.patch('a.b.ClassC') as class_c:
instance = class_c.return_value # instance returned by ClassC()
b = ClassB()
b.method1()
assert instance.method3.called == True