Mock function called on import - python

I have a module I need to test that calls a function on import but I cannot call this function for various reasons. So I am mocking this function but even mocking it calls import.
For example I am testing mod1.py that looks like this:
import os
def bar():
return 'foo'
def dont_call():
os.listdir("C:\\tmp")
dont_call()
And my test looks something like this:
import mock
#mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()
The problem is os.listdir is called.
I cannot change mod1 so what can I do?
I am using python2.7.
To put this in context I am testing a module that opens a database connection on import which I do not agree with but I can see the reasoning behind it. Unfortunately I cannot access this database on my QA machine.

If you want code to 'not' be executed on import put them inside the following condition:
In mod1.py, do the following:
if __name__=="__main__":
dont_call()
This is because, by default when you import a python module, all the code in it gets executed. By adding the above condition, you are explicitly stating that dont_call() is to be called only when the file it run as a script and not when it is imported in other modules.

The workaround I found was to mock what dont_call was calling giving me something like this:
import mock
#mock.patch("os.listdir")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()

Check your dir
$tree.
test_shot/
├── mod1.py
├── __pycache__
│ └── mod1.cpython-310.pyc
└── test.py
Below code works fine for me.
mod1.py
import os
def bar():
return 'foo'
def dont_call():
os.listdir(".")
def call_this():
print('called this')
call_this()
dont_call()
test.py
import mock
#mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()
Here is output:
$cd test_shot
$python3 test.py
called this

Related

Python unittest with TestLoader results in ModuleNotFoundError

i try to run a unittest with unittest.TestLoader and unittest.TextTestRunner but get an ModuleNotFoundError everytime i try to run the 'main' test file (here: test_all.py). I have the following file structure:
src.
test_all.py
dir1.
__init__.py
module1.py
submodule1.py
test_module1.py
dir2.
__init__.py
module2.py
submodule2.py
test_module2.py
dir3.
...
The test_all.py file looks like this:
# test_all.py
import os
import unittest
loader = unittest.TestLoader()
suite = loader.discover(os.getcwd())
runner = unittest.TextTestRunner()
runner.run(suite)
And finally the structure of the single testcases look like this:
# test_module1.py
import unittest
from module1 import Module1
class Module1TestCase(unittest.TestCase):
def setUp(self):
# do something
def test_something(self):
# test test
def tearDown(self):
# do something
if __name__ == '__main__':
unittest.main()
So, running the test_all.py always results in an ModuleNotFoundError referencing to the from module1 import Module1 inside the TestCase test_module1.py (and the same in the following TestCases). As far as i can tell there are no circular dependencies. Maybe adding the current Path to the PythonPath would work, but it really makes no sense to me: on the one hand i run the test_all.pyas main in the current directory and on the other the unittest.TestLoader.discover() already takes the current path.
PS: I know that putting all the TestCases in one folder is way better. But first i want to figure out why this is not working. Thanks!

Function patch not being picked up by imported module

I feel like this should be an easy mock, but I have not gotten it to work yet.
I am working off of the following directory structure:
module
├── utilities.py
├── order.py
├── test
│ ├── test_order.py
The relevant code is as follows:
-- utilities.py --
def get_file_path(order_number, file_extension):
# this is what I want to mock out
-- order.py --
from module.utilities import get_file_path
class Order():
# ...
#classmethod
def load_order(order_number, extension):
file_path = get_file_path(order_number, extension)
-- test_order.py --
import unittest
from unittest.mock import patch
from module.order import order
#patch('order.get_file_path')
def mock_file(_, extension):
if extension == 'json':
return static_file_path
class TestOrder(unittest.TestCase):
def test_load_order_by_number(self):
my_order = order.load_order(number, extension)
This is the first time that I have tried mocking in Python. From what I can tell, what I have should work, but whenever an Order calls get_file_path, it always uses the one in utilities.py.
I have tried:
decorating test_load_order_by_number
patching with module.order.get_file_path
I tried looking on SO but none of the solutions that I found helped, so I thought that I was just doing something obviously wrong that someone can point out.
It does not look like creating the patch outside of the class was getting picked up. It started working when I pulled the patch in as a decorator for the specific test.
class TestOrder(unittest.TestCase):
#patch('utilities.order.get_file_path')
def test_load_order_by_number(self, file_mock):
def mock_get_file_path(*args, **kwargs):
if kwargs.get('extension', None) == 'json':
return static_file_path
return None
file_mock.side_effect = mock_get_file_path
my_order = order.load_order(number, extension)

Python, Mockito, Mocking Another Module's Imports

Suppose I have module1.py
from my_library import useful_function
def do_something(x):
return useful_function(x)
I am testing module2.py
from module1 import do_something
def do_something_else(x):
return do_something(x+1)
useful_function does database calls, and I would therefore like to stub it out to return a constant value.
How can I use mockito to stub out useful_function? I have tried importing my_library, and using
when( my_library ).useful_function('abc').thenReturn(...)
but that does not work. If I pause Eclipse and hover over the useful_function line inside do_something(), it appears that useful_function() has not been stubbed.
import module1
module1.useful_function = Mock(...)
return do_something(x+1)

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
"""

python: I need to understand better imports and packages

My application has a structure similar to this one:
myapp.py
basemod.py
[pkg1]
__init__.py
mod1.py
[pkg2]
__init__.py
mod2.py
myapp.py:
import pkg1
import pkg2
if __name__ == '__main__':
pkg1.main()
pkg2.main()
basemod.py:
import pkg1
def get_msg():
return pkg1.msg
pkg1/__init__.py:
import mod1
msg = None
def main():
global msg
mod1.set_bar()
msg = mod1.bar
pkg1/mod1.py:
bar = None
def set_bar():
global bar
bar = 'Hello World'
pkg2/__init__.py:
import mod2
def main():
mod2.print_foo()
pkg2/mod2.py:
import basemod
foo = basemod.get_msg()
def print_foo():
print(foo)
If I run myapp.py I get:
None
While in my mind I'd expect:
Hello World
My goal is to keep the two packages completely independent from each other, and only communicating through basemod.py, which is a sort of API to pkg1.
I'm starting to think that I have not completely understood how imports among packages work, what am I doing wrong?
Thank you!
Took me a while to read through all that code, but it looks like your problem is in pkg2/mod2.py. The line foo = basemod.get_msg() is executed the first time that file is imported, and never again. So by the time you change the value of mod1.bar, this has already executed, and foo is None.
The solution should simply be to move that line into the print_foo function, so it is only executed when that function is called - which is after the code that sets the relevant value.

Categories