How do I mock a class from a different module in Python? - python

In Python I have 3 files in the same folder: file1.py, file2.py and test.py
file1.py contains a simple class definition
class MyClass:
def __init__(self, a, b):
self.a = a
self.b = b
print(f"a={a} and b={b}")
file2.py instantiate previous class
from file1 import MyClass
def instantiate_class():
o = MyClass(1,2)
In test.py I'm trying to mock the file1.MyClass from instantiate_class() function
from unittest.mock import patch
from file2 import instantiate_class
with patch("file1.MyClass") as mock_check:
instantiate_class()
print(mock_check.call_args)
Problem is that class MyClass from file2.py is not mocked as the print from the MyClass constructor is called.
Only solution I found to solve this is to change file2.py with:
import file1
def instantiate_class():
o = file1.MyClass(1,2)
Is there a solution to obtain mocking that does not involve changing file1.py and file2.py? I only want to change the test.py file (writing unit tests for existing classes).

I need to mock the file2.mock instead of file1.mock. Like below:
from unittest.mock import patch
from file2 import instantiate_class
with patch("file2.MyClass") as mock_check:
instantiate_class()
print(mock_check.call_args)
reference
where-to-patch

Related

Mocking a method inside class in python test

I am new to Python and writing a unit test for the already existing code.
I have the following Python code structure:
root_project:
-- src
-- signUp
-- __init__.py
-- abc.py
-- xyz.py
abc.py contains the following code:
from . import xyz
class Abc:
def __init__(self):
pass
def start_process(self):
xyz.start_timer()
I want to mock xyz.start_timer() inside method start_process of class Abc so that start_timer() mock version can be used.
How can I achieve this?
You can simply patch the start_timer function using mock.patch().
abc.py
import xyz
class Abc:
def __init__(self):
pass
def start_process(self):
xyz.start_timer()
test_abc.py
from unittest import mock, TestCase
from abc import Abc
class Test_Abc(TestCase):
#mock.patch("abc.start_timer")
def test_start_process(self, mock_start_timer):
# your test code
Notice that I have patched abc.start_timer and not xyz.start_timer.
You just need to patchxyz.start_timer(), I just added return to start_process to show that the patching really does what it should:
import xyz
import unittest
from unittest import mock
class Abc:
def __init__(self):
pass
def start_process(self):
return xyz.start_timer()
class Test_Abc(unittest.TestCase):
#mock.patch('xyz.start_timer', return_value=True)
def test_start_process(self, start_process):
a = Abc()
self.assertTrue(a.start_process())
if __name__ == '__main__':
unittest.main()
Out:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Create a class with static functions? - Python

I need to have this import specifically in the class to prevent my tests having to include the imports for each test (they can't be declared outside because of circular dependency issues with the entire codebase).
I am trying to declare my imports in a class, and access what I need with functions but not too sure how to make this work so that any test can call the functions and get what we need.
I have this at the moment:
class KTestHelper:
""" Small helper class for retrieving our hook and constants"""
from fd.fdee import (
IMOLDER,
KDER,
)
p3 = P3Hook()
#staticmethod
def get_imolder(self) -> str:
return self.IMOLDER
#staticmethod
def get_kder(self) -> str:
return self.KDER
#staticmethod
def get_p3_hook(self) -> P3Hook:
return self.p3
self obviously no longer exists as i added #staticmethod but now i'm not sure how to get it to work properly.
I need to be able to do KTestHelper.get_imolder() on every test function / some test functions that need it.
This strategy isn't enough to prevent the module import. The class will be constructed during the module load and the class attributes get evaluated. Example:
test/
__init__.py
a.py
b.py
c.py
a.py
print("loading module a")
class A:
pass
b.py
print("loading module b")
class B:
from .a import A
c.py
from test.b import B
This will output:
loading module b
loading module a
If you want this to work you'll need to put the import line in the class methods themselves.
print("loading module b")
class B:
#classmethod
def a(cls):
from .a import A
return A

Python import on sub-folders

It`s been a while since I create my classes and import them to my script, using
from <folder> import <file>
and my file.py looks like this:
class myClass:
def __init__():
and so on.
However, whenever I want to use this class on my main script, I have to do:
file.myClass()
Is thera a better way so I could use only "myClass()"?
I have recreated the scenario with the following directory structure:
.
├── outer.py
└── some_folder
└── inner.py
You missed the self in __init__ method:
some_folder/inner.py:
class myClass:
def __init__(self):
print("myClass is initiated")
Import the class from the file when you want to directly use the class name.
outer.py:
from some_folder.inner import myClass
some_object = myClass()
Output:
myClass is initiated
Instead of importing the file, you can import the class
from package.module import MyClass

unittest mock how to mock a method being called

I want to test that method a calls method b. These methods are in separate files, and are not a part of class object.
# file_a.py
from file_b import b
def a():
b()
# file_b.py
def b():
test
import unittest
from unittest import mock
from file_a import a
class MyTestCase(unittest.TestCase):
#mock.patch('file_b.b')
def test_b_called(self, mock):
a()
mock.assert_called()
if __name__ == "__main__":
unittest.main()
This fails with AssertionError: Expected 'b' to have been called.
Is there a right way to do this?
When you import a function into the current namespace, like in your example, the function will need to be patched in that namespace. In your case, you need:
#mock.patch('file_a.b')
You would patch file_b.b if you had done the import and use like this:
import file_b
def a():
file_b.b()

Override module method where from...import is used

I have a problem overriding the method where from...import statement is used. Some example to illustrate the problem:
# a.py module
def print_message(msg):
print(msg)
# b.py module
from a import print_message
def execute():
print_message("Hello")
# c.py module which will be executed
import b
b.execute()
I'd like to override print_message(msg) method without changing code in a or b module. I tried in many ways but from...import imports the original method. When I changed the code to
import a
a.print_message
then I see my change.
Could you suggest how to solve this problem?
------------------ Update ------------------
I tried to do that like below e.g.:
# c.py module
import b
import a
import sys
def new_print_message(msg):
print("New content")
module = sys.modules["a"]
module.print_message = new_print_message
sys.module["a"] = module
But this is not working where I'm using for...import statement. Is working only for import a but as I wrote I don't want change code in b.py and a.py modules.
With your a and b modules untouched you could try implementing c as follows:
import a
def _new_print_message(message):
print "NEW:", message
a.print_message = _new_print_message
import b
b.execute()
You have to first import a, then override the function and then import b so that it would use the a module that is already imported (and changed).
module1.py
def function1():
print("module1 function1")
function2()
def function2():
print("module1 function2")
module2.py
import module1
test = module1.function1()
print(test)
""" output
module1 function1
module1 function2
"""
def myfunction():
print("module2 myfunction")
module1.function2 = lambda: myfunction()
test = module1.function1()
print(test)
"""output
module1 function1
module2 myfunction
"""

Categories