Python, Mockito, Mocking Another Module's Imports - python

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)

Related

Python : Mock a module that raises an exception

I need to test a function in a module that import another module which raises an exception when imported.
#a.py
raise ValueError("hello")
my_const = 'SOMETHING'
#b.py
from a import my_const
def foo():
# do something with my_const
return "expected_result"
#test_foo.py
def test_foo():
from b import foo
assert foo() == "expected_result"
Here when I import foo in test_foo.py, a.py get imported in b.py, an exception is raised and the import is never completed so my_const is not available in b.py.
I'm not allowed to modify neither a.py or b.py. Also, using unittest.patch and #patch('a', 'my_const') does import a.py so it doens't work.
It is possible create the module dynamically with the import lib and add it to sys.modules, but is there another solution that doesn't require importlib ?
As far as I know, you can create and importe the module dynamically. Here is a code inspired from the
"Approximating importlib.import_module()" section in the import lib documentation
from importlib.util import module_from_spec, find_spec
import sys
def patched_import(name, **kwargs):
    spec = find_spec(name)
    m = module_from_spec(spec)
    for k in kwargs:
     setattr(m, k, kwargs[k])
    sys.modules[name] = m
Edit: My solution should be ok for a mock-up but be careful as manipulation of referential can have side effects.
To use it, just do:
patched_import('a', my_const='stuff')
Before importing b.py.

How to mock variable in included library

Folks,
I have a problem during including file.py to test_file.py namely:
file.py uses Robot library BuiltIn:
from robot.libraries.BuiltIn import BuiltIn
DEFAULT_IPHY_TTI_TRACE_DIR =
os.path.join(BuiltIn().get_variable_value('${OUTPUT_DIR}'), 'iphy_tti_trace')
And when I try to include file.py in my test_file.py
import pytest
#import file.py
I receive:
test_file.py:8: in <module>
/opt/ute/python/lib/python2.7/site-packages/robot/libraries/BuiltIn.py:1331: in get_variable_value
return self._variables[self._get_var_name(name)]
/opt/ute/python/lib/python2.7/site-packages/robot/libraries/BuiltIn.py:75: in _variables
return self._namespace.variables
/opt/ute/python/lib/python2.7/site-packages/robot/libraries/BuiltIn.py:71: in _namespace
return self._get_context().namespace
/opt/ute/python/lib/python2.7/site-packages/robot/libraries/BuiltIn.py:66: in _get_context
raise RobotNotRunningError('Cannot access execution context')
E RobotNotRunningError: Cannot access execution context
How can I mock this? This is posible at all?
Sure, the issue is just that you can't mock the BuiltIn class where it is used (in file.py). You have to mock the class where it is declared (in robot.libraries.BuiltIn).
Using mocks:
from unittest.mock import patch, MagicMock
def _test_default_iphy_tti_trace_dir():
with patch('robot.libraries.BuiltIn.BuiltIn.get_variable_value', return_value='/foo/bar'):
import file
assert file.DEFAULT_IPHY_TTI_TRACE_DIR == '/foo/bar/iphy_tti_trace'
Using monkeypatch fixture:
def test_default_iphy_tti_trace_dir(monkeypatch):
def mocked_get(self, name):
return '/foo/bar'
monkeypatch.setattr('robot.libraries.BuiltIn.BuiltIn.get_variable_value', mocked_get)
import file
assert file.DEFAULT_IPHY_TTI_TRACE_DIR == '/foo/bar/iphy_tti_trace'
Also note that the mocking is done for the scope of a single test only, so you can't import file on top of the test module as the BuiltIn will be unpatched there, raising the context error.

Mock function called on import

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

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

Mocking Functions Using Python Mock

I am trying to Mock a function (that returns some external content) using the python mock module.
I'm having some trouble mocking functions that are imported into a module.
For example, in util.py I have
def get_content():
return "stuff"
I want to mock util.get_content so that it returns something else.
I am trying this:
util.get_content=Mock(return_value="mocked stuff")
If get_content gets invoked inside another module, it never actually seems to return the mocked object. Am I missing something in terms of how to use Mock?
Note that if I invoke the following, things work correctly:
>>> util.get_content=Mock(return_value="mocked stuff")
>>> util.get_content()
"mocked stuff"
However, if get_content is called from inside another module, it invokes the original function instead of the mocked version:
>>> from mymodule import MyObj
>>> util.get_content=Mock(return_value="mocked stuff")
>>> m=MyObj()
>>> m.func()
"stuff"
Contents of mymodule.py
from util import get_content
class MyObj:
def func():
get_content()
So I guess my question is - how do I get invoke the Mocked version of a function from inside a module that I call?
It appears that the from module import function may be to blame here, in that it doesn't point to the Mocked function.
The general case would be to use patch from mock. Consider the following:
utils.py
def get_content():
return 'stuff'
mymodule.py
from util import get_content
class MyClass(object):
def func(self):
return get_content()
test.py
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
#patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
Note how get_content is mocked, it is not util.get_content, rather mymodule.get_content since we are using it in mymodule.
Above has been tested with mock v2.0.0, nosetests v1.3.7 and python v2.7.9.
I think I have a workaround, though it's still not quite clear on how to solve the general case
In mymodule, if I replace
from util import get_content
class MyObj:
def func():
get_content()
with
import util
class MyObj:
def func():
util.get_content()
The Mock seems to get invoked. It looks like the namespaces need to match (which makes sense). However, the weird thing is that I would expect
import mymodule
mymodule.get_content = mock.Mock(return_value="mocked stuff")
to do the trick in the original case where I am using the from/import syntax (which now pulls in get_content into mymodule). But this still refers to the unmocked get_content.
Turns out the namespace matters - just need to keep that in mind when writing your code.
You have to patch the function where it is being used. In your case that would be in the mymodule module.
import mymodule
>>> mymodule.get_content = Mock(return_value="mocked stuff")
>>> m = mymodule.MyObj()
>>> m.func()
"mocked stuff"
There is a reference in the docs here: http://docs.python.org/dev/library/unittest.mock.html#where-to-patch
Let's assume you're creating your mock inside module foobar:
import util, mock
util.get_content = mock.Mock(return_value="mocked stuff")
If you import mymodule and call util.get_content without first importing foobar, your mock will not be installed:
import util
def func()
print util.get_content()
func()
"stuff"
Instead:
import util
import foobar # substitutes the mock
def func():
print util.get_content()
func()
"mocked stuff"
Note that foobar can be imported from anywhere (module A imports B which imports foobar) as long as foobar is evaluated before util.get_content is called.
While it doesn't provide an answer to your question directly, another possible alternative is to transform your function to a static method using the #staticmethod.
So you could transform your module utils into a class using something like:
class util(object):
#staticmethod
def get_content():
return "stuff"
Then mock patches it correctly.

Categories