Mocking a function with namespace confusion - python

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.

Related

How to patch a module method that is called within a class?

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.

Testing class initializer using unittest in python

I am using unittest module for writing tests.
I need to test initialization of the object inside a testcase using different inputs.
For this purpose I am importing the class inside setUp(). But when I try to use the class inside test_*() functions, I get this error - NameError: name 'Example' is not defined
Here is my code sample-
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
import Example
def test_sample_function(self):
e = Example(1,2)
I know that I can simply import the class at top of the script. But I do not want to do that. I need to import it only during setup of the testscript.
Looking for some help here.
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
import Example
self.Example = Example
def test_sample_function(self):
e = self.Example(1,2)
There's no reason to import the module in setUp. The module is still available globally in sys.modules, but you've only bound it to a local name that goes away after setUp returns. Just import it globally.
import unittest
import Example
class TestExample(unittest.TestCase):
def test_sample_function(self):
e = Example(1,2)

How do I patch object imported by another python file?

Example abc.py:
from pack.def import Def
class Abc(object):
def f(self):
return Def().response()
Example test_abc.py
from unittest import mock, TestCase
from pack.abc import Abc
class TestAbc(TestCase):
#mock.patch('pack.def.Def')
def test_f(self, mock_def):
responses = ['response1', 'response2', 'response3']
mock_def.return_value.response.return_value = responses
assert responses == Abc().f()
I assumed the mock def has been patched, but I'm doing something wrong, does someone know I'm doing wrong?
You must mock the object your are working. You are using the Def that belongs to pack.def package in abc module. When you write test for Abc class, and want to mock Def calls, you must mock the Def that is imported in abc, not from original module.
Use #mock.patch('pack.abc.Def') instead of #mock.patch('pack.def.Def').

Patching a module imported and instantiated in the SUT

I'm trying to run unit tests on a class that imports two other modules, and I'm trying to patch out those modules using mock. One of these modules is instantiated in the class I'm testing, and I have not been able to patch it out. It appears that I have managed to patch out the other one.
What is the best way to patch out the sequence.processor module in this code?
Directory structure
logger.py
parser/
__init__.py
docparser.py
sequence/
__init__.py
processor.py
tests/
testdocparser.py
/parser/docparser.py
import logger
from sequence.processor import Processor
class DocParser(object):
def __init__(self, reader_writer):
self.processor = Processor(reader_writer)
def write_and_parse(self, products):
logger.log(products)
self.processor.process(products)
/tests/testdocparser.py
import unittest
from mock import MagicMock, patch
from parser import docparser
class DocParserTests(unittest.TestCase):
def setUp(self):
self.mock_writer = MagicMock()
self.docparser = docparser.DocParser(self.mock_writer)
#patch("parser.docparser.logger") # This seems to be patched properly
#patch("parser.docparser.Processor") # This is not patched
def test_write_and_parse(self, mock_logger, mock_proc):
products = "products"
self.docparser.write_and_parse(products)
You patch Processor in test_write_and_parse() but it's instantiated in DocParser.__init__() which is called from setUp().
This should work, though I haven't tested it:
class DocParserTests(unittest.TestCase):
def setUp(self):
self.mock_writer = MagicMock()
with patch('parser.docparser.Processor'):
self.docparser = docparser.DocParser(self.mock_writer)
#patch("parser.docparser.logger")
def test_write_and_parse(self, mock_logger):
products = "products"
self.docparser.write_and_parse(products)
I've used context manager instead of decorator to avoid changing setUp() signature (adding an argument).
Also the order of mock arguments for test_write_and_parse() is incorrect in your code. Here's an excerpt from mock docs:
When you nest patch decorators the mocks are passed in to the decorated function in the same order they applied (the normal python order that decorators are applied). This means from the bottom up...
Correct order:
#patch("parser.docparser.logger") # This seems to be patched properly
#patch("parser.docparser.Processor") # This is not patched
def test_write_and_parse(self, mock_proc, mock_logger):
# ...
Of cource, it doesn't really matter in your particular case because mock_proc and mock_logger are not used later.

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