How can I mock the class "ClassA" in the test by replacing it completely If I have a class created through a factory method?
├── main.py
├── src
│ ├── core.py
│ ├── facade.py
│ ├── factory.py
│ └── something
│ ├── class_a.py
│ ├── class_b.py
│ ├── class_c.py
│ └── interface.py
└── tests
└── test_core.py
class_a.py
from src.something.interface import Interface
class ClassA(Interface):
def function(self):
print('I\'m class A')
class_b.py
from src.something.interface import Interface
class ClassB(Interface):
def function(self):
print('I\'m class B')
class_c.py
class ClassC:
def function(self):
print('I\'m class C')
interface.py
from abc import ABC, abstractmethod
class Interface(ABC):
@abstractmethod
def function(self):
pass
facade.py
from src.something.class_c import ClassC
from src.something.interface import Interface
class Facade:
def __init__(self, interface: Interface, class_c: ClassC):
self.function = interface
self.class_c = class_c
def functionClass(self):
self.function.function()
def functionAnotherClass(self):
self.class_c.function()
factory.py
from src.facade import Facade
from src.something.class_a import ClassA
from src.something.class_b import ClassB
from src.something.class_c import ClassC
class Factory:
@staticmethod
def build(config: str):
if config == 'A':
return Facade(ClassA(), ClassC())
elif config == 'B':
return Facade(ClassB(), ClassC())
else:
raise ValueError("Error factory")
core.py
from src.factory import Factory
class Core:
def __init__(self):
self.__unit = Factory.build('A')
def run(self):
self.__unit.functionClass()
self.__unit.functionAnotherClass()
main.py
from src.core import Core
if __name__ == '__main__':
core = Core()
core.run()
test_core.py
import unittest
from unittest.mock import patch
from src.core import Core
class MockClassA:
def function(self):
print('I\'m mock class A')
class TestCore(unittest.TestCase):
@patch('src.something.class_a.ClassA', new=MockClassA)
def testOne(self):
core = Core()
core.run()
pass
I expect that ClassA will be replaced with a mock class and the factory will send a locked object to the facade, however this does not happen when the test is run, it is output
OK
Process finished with exit code 0
I'm class A
I'm class C
Although I expect that it will be
Ran 1 test in 0.001s
OK
Process finished with exit code 0
I'm mock class A
I'm class C
can you tell me how to replace a class with such a code?
using 'src.factory.ClassA' instead of 'src.something.class_a.ClassA' or mocking the attribute of ClassA work, but the other one does not because the @patch does not change references of the class.
class TestCore(unittest.TestCase):
@patch('src.factory.ClassA', new=MockClassA)
def testOne(self):
core = Core()
core.run()
pass
@patch('src.something.class_a.ClassA.function', lambda _: print('I\'m mock 2 class A'))
def testTwo(self):
core = Core()
core.run()
pass