python mocking function calls that are called during module import - python-3.x

I need to perform mocking for python code that is running during module import
For example I have code like this
import configparser
config = configparser.ConfigParser()
config.read('test.ini')
a = float(config['config']['a'])
b = float(config['config']['b'])
c = float(config['config']['c'])
print(a)
print(b)
print(c)
I need mock "config" for testing
import pytest
import mock
import app
#mock.patch('app.configparser.ConfigParser')
def test_config_mock(config_mock):
config_mock.return_value = {'config': { 'a' : 1 } }
However, this testing function being called after actual import so my mocking is not making any sense
What's the right way of doing this kind of thing?

What you can do in this case is to instead patch the config instance using mock.patch.dict:
# test_coolio.py
import mock
from app.fun import coolio
#mock.patch.dict('app.configparser.config', values={'config': {'a': 15}})
def test_config_mock():
assert coolio() == '15'
# app/fun.py
from app.configparser import config
def coolio():
return config['config']['a']

Related

Not able to create mock object using mocker

I am trying to create mock object for unit testing but somehow always actual object is called.
Below is the code for reference:-
utility_functions.py
import os
import json
def get_module_configurations(key):
config = os.getcwd()
config = config + "\\xyz.json"
with open(config) as f:
module_config = json.load(f)
module_config = module_config[key]
return module_config
load_class
from importlib import import_module
from inspect import isclass, isabstract
def load_module(data):
package_path = data['Package']
module_name = data['ModuleName']
class_name = data['ClassName']
try:
module_name = str(module_name.split('.py')[0])
module = import_module('.' + module_name, package_path)
except Exception as error:
pass
try:
_class = getattr(module, class_name)
except Exception as error:
pass
if isclass(_class) and not (isabstract(_class)):
return _class
else:
return None
function1.py
import load_class
from utility_functions import get_module_configurations
def load_helpers(task_name):
module = get_module_configurations(task_name)
cls = load_class.load_module(module)
return cls
test_function.py
import pytest
from function1 import load_helpers
def test_mock(mocker):
class_to_load = {"Package": "Test", "ModuleName": "default_class.py", "ClassName":
"DefaultClass"}
mocker.patch('function1.load_helpers', return_value= class_to_load)
result = load_helpers('c')
assert result is not None
Since I am mocking, load helpers should not be called but it always calls actual implementation saying path is invalid.
I am missing something basic but cannot figure out what.
Any help will be great.
If you are importing the function into your module (from function1 import load_helpers), you need to patch it as if it was part of it. This means that instead of...
mocker.patch('function1.load_helpers', return_value=class_to_load)
...you should use...
mocker.patch('test_function.load_helpers', return_value=class_to_load)
PS: I assume that you are just practicing mocking because otherwise your test function doesn't make sense.

How to Unittest sys.argv with multiple values

Let's say I have a Python script file that uses sys.argv variables. And I want to test the sys.argv with different values in multiple tests. The issue is that I have to patch and import it multiple times but i think it holds the sys.args values only from the first import so both TestCases print the same values ['test1', 'Test1']. Is my approach wrong?
example.py
import sys
ex1 = sys.argv[0]
ex2 = sys.argv[1]
print(ex1)
print(ex2)
test_example.py
import unittest
import mock
import sys
class TestExample(unittest.TestCase):
#mock.patch.object(sys, 'argv', ['test1', 'Test1'])
def test_example1(self):
import example
#mock.patch.object(sys, 'argv', ['test2', 'Test2'])
def test_example2(self):
import example
The problem is that Python will not (unless you work hard at it) reimport the same file more than once.
What you should do is have the import only define stuff, and define a main() function in your module that gets called when it's time to run stuff. You call this main() function directly in the script when the script is called by itself (see the last two lines of example.py below), but then you can also call that function by name during unit testing.
For what it's worth, this is best practice in Python: your scripts and module should mostly define functions, classes and whatnot on import, but not run much. Then you call your main() function in a __name__ guard. See What does if __name__ == "__main__": do? for more details about that.
Here's your code modified to work, testing your module with two different sets of sys.argv values:
example.py:
import sys
def main():
ex1 = sys.argv[0]
ex2 = sys.argv[1]
print(ex1)
print(ex2)
if __name__ == "__main__":
main()
test-example.py:
import unittest
import mock
import sys
import example
class TestExample(unittest.TestCase):
#mock.patch.object(sys, 'argv', ['test1', 'Test1'])
def test_example1(self):
example.main()
#mock.patch.object(sys, 'argv', ['test2', 'Test2'])
def test_example2(self):
example.main()
Results from python -m unittest:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
test1
Test1
test2
Test2

Is it possible to make a module available as an import from another module?

I'm refactoring some code and have moved around some files. But for backwards compatibility, I would like to make all of my modules keep their old import paths.
my file structure is as follows
--| calcs/
----| __init__.py
----| new_dir
------| new_file1.py
------| new_file2.py
What do I need to do ensure that I can use an import like
import calcs.newfile1.foo
# OR
from calcs.newfile1 import foo
I have tried a few methods of adding the imports to the top level __init__.py file. As is reccommended here
But while this seems to allow an import such as import calcs.newfile1, An import such as import calcs.newfile1.foo raises ModuleNotFoundError: No module named calcs.newfile1
I expect that I need python to recognize calcs.newfile1 as a **module **. At the moment it seems to just be importing it as a class or other object of some sort
The only way i know how to do it is by creating a custom import hook.
Here is the PEP for more information.
If you need some help on how to implement one, i'll suggest you to take a look at the six module,
here
and here
Basically your calcs/__init__.py will become like this:
''' calcs/__init__.py '''
from .new_dir import new_file1, new_file2
import sys
__path__ = []
__package__ = __name__
class CalcsImporter:
def __init__(self, exported_mods):
self.exported_mods = {
f'{__name__}.{key}': value for key, value in exported_mods.items()
}
def find_module(self, fullname, path=None):
if fullname in self.exported_mods:
return self
return None
def load_module(self, fullname):
try:
return sys.modules[fullname]
except KeyError:
pass
try:
mod = self.exported_mods[fullname]
except KeyError:
raise ImportError('Unable to load %r' % fullname)
mod.__loader__ = self
sys.modules[fullname] = mod
return mod
_importer = CalcsImporter({
'new_file1': new_file1,
'new_file2': new_file2,
})
sys.meta_path.append(_importer)
and you should be able to do from calcs.new_file1 import foo

How to MagicMock the function within function python

I have a module A, which contains below two functions:
def my_func():
my_dict = {"key1":100, "key2": 100}
send_result(dicts=my_dict)
def send_result(dicts):
print(dicts)
I have written unit test case as below:
from unittest.mock import MagicMock
import A
def test_send_results(self, dicts):
self.assertGreater(len(dicts), 0)
def test_my_func(self):
A.send_result = MagicMock(wraps=self.test_send_results)
A.my_func()
And when I am running unit test case, I am getting below error though dicts contains the value:
TypeError: test_send_results() missing 1 required positional argument: 'dicts'
As suggested by Anthony, use patch.object. An example given below:
import unittest
from unittest import mock
import A
class MyTestClass(unittest.TestCase):
def test_send_results(self, dicts):
self.assertGreater(len(dicts), 0)
#mock.patch.object(self, 'test_send_results')
def test_my_func(self, mock_func):
mock_func.return_value = 'something'
A.my_func()

Dynamically import in python through a Dictionary

I need to import modules using a dictionary, I would like to loop through the dictionary and import it. For example
items = {
'Initial_Load': 'initial_load',
'Disclaimer': 'disclaimer_tests',
'Menu': 'menu_tests'
}
Those items should convert into
from Inital_Load import initial_load
from Disclaimer import disclaimer_tests
from Menu import menu_tests
Is it even possible?
This uses importlib.import_module to import the module, then getattr to resolve the name from that modules namespace:
from importlib import import_module
def import_dict(d):
result = {}
for module_name, attr_name in d.items():
module = import_module(module_name)
result[attr_name] = getattr(module, attr_name)
return result
import_dict({"math": "sqrt"})["sqrt"](4)
# 2.0

Resources