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.
Related
Here the ABC() and obj.print_1() get called during the import time and it prints "making object" and "printed 1" respectively. How can we mock all the three functions, __init__(), print_1(), and print_2()?
xyz.py
from abc import ABC
obj = ABC()
obj.print_1()
def func():
return obj.print_2(2)
abc.py
class ABC():
def __init__(self):
print("making object")
def print_1(self):
print("printed 1")
return None
def print_2(self, val):
print("printed ", val)
return None
Indeed, as soon as you import xyz, it will import abc and create an instance then call a method on it.
Solution : import abc yourself BEFORE xyz EVER GETS IMPORTED, and mock the methods defined in the class. And because we can't import a method, patch.object is required.
Note : I added a self as parameter in your ABC.print_1 method, otherwise it would be incorrect. Otherwise make it #staticmethod
Here is the test file I used :
import unittest
import unittest.mock as mock
from so74709409_abc import ABC
# no import of `xyz` here !
class Tests(unittest.TestCase):
def test__xyz_obj_calls_print1(self):
# __init__ must return None
with mock.patch.object(ABC, "__init__", **{"return_value": None}) as mock_init, \
mock.patch.object(ABC, "print_1") as mock_print1, \
mock.patch.object(ABC, "print_2") as mock_print2:
from so74709409_xyz import func # import now !
func()
mock_init.assert_called_once()
mock_print1.assert_called_once_with()
mock_print2.assert_called_once_with(2)
if __name__ == "__main__":
unittest.main()
But this is not very robust, if the module was already imported (maybe indirectly) before the test run, the import inside the test won't have any effect, and so it will fail (mocks not getting called). It can be a pain in a real test suite (with many tests running in sequence) because the previous test will already have imported xyz.
That's why it's better to do these kind of things in a if __name__=="__main__", or in a function called deliberately.
(beware : I assume you choose abc as a dummy name, but it is actually a standard library module for Abstract Base Classes)
How do you make Python's unittest.mock.patch return an object that lets you assign a callable return value?
For example, I have a custom class in myclass.py defined as:
class MyClass:
#property
def someprop(self):
return 'you should never see this in a test'
I want to test a function that acts on data retrieved from someprop. In my real application, someprop actually calls some complicated external database that's not accessible in a unittest, and isn't really necessary for the purposes of the unittest, so I decide to mock a return value using the patch and the faker package.
So my unittest looks like:
import unittest
import unittest.mock
from faker import Faker
from myclass import MyClass
class Tests(unittest.TestCase):
#unittest.mock.patch('myclass.MyClass.someprop')
def test_mock_error(self, mock_myclass_someprop):
class RandomText:
#property
def text(self):
factory = Faker()
return factory.text()
# Make calls to someprop return random text.
mock_myclass_someprop.return_value = RandomText.text
a = MyClass()
actual_text = a.someprop
print('actual text:', actual_text)
self.assertTrue('MagicMock' not in str(actual_text)) # this fails
if __name__ == '__main__':
unittest.main()
Every time the test runs, the patch causes it to access the text property on my RandomText instance instead of someprop, which should return a unique string. However, this fails because the mock is actually returning a value like <MagicMock name='someprop' id='140126618001360'>.
Why is this, and how do I fix it?
I've tried refactoring how I set and call return_value, but no matter what I do, it returns a MagicMock instance instead of a real return value retrieved from my patched callable.
I have the following structure:
# create.py
import sshHandler
class Create:
def __init__(self):
self.value = sshHandler.some_method()
# sshHandler.py
def some_method():
return True
If I kow try to patch sshHandler.some_method it will not work as expected
from unittest import TestCase
from unittest.mock import patch
import create
class TestCreate(TestCase):
#patch("sshHandler.some_method")
def test_create(self, mock_ssh):
mock_ssh.return_value = False
c = create.Create()
# c.value = True but should be false
The result I am looking for is that some_method would be patched in create as well (and return false). If I just call some_method in the context of test_create it works as expected. How do I fix the patch so that it is also active in the Create class when accessing sshHandler?
I saw this question Why python mock patch doesn't work?, but couldn't solve my problem with the information given there.
You've patched the wrong module. Instead patch the sshHandler.some_method patch create.sshHandler.some_method. You must patch the object of module you're handling.
I am trying to mock a function that should get called when calling a class method:
# SomeClass.py
from some_module import some_function
class SomeClass:
def some_method(self, *a, **kw):
...
some_function()
...
# tests.py
from mock import patch
from some_package.SomeClass import SomeClass
class TestSomeClass:
#patch('SomeClass.some_function') # <- error
def test__some_function__called(self, mocked_function):
...
SomeClass().some_method()
mocked_function.assert_called()
However, I keep getting an error saying that SomeClass does not have a method called some_function.
The issue is due to the fact that the module name and the class name are the same, i.e. SomeClass. This is causing patch some confusion.
The solution: a combination of importlib and overriding the imported modules function with Mock():
# tests.py
import importlib
from mock import Mock
from some_package.SomeClass import SomeClass
class TestSomeClass:
def test__some_function__called(self):
some_class_module = importlib('some_package.SomeClass') # this is the actual module
some_class_module.some_function = Mock()
...
SomeClass().some_method()
some_class_module.some_function.assert_called() # <- no more error - tests pass
This is how I solved this issue - if anyone has an alternative solution it would be great to hear it. Hope this helps anyone with a similar issue.
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.