python unittest.mock.patch strange behaviour - python

I use unittest in my testing. I import a class in yhab.main package as...
from yhab.blah import SomeClass
def some_func():
some_instance = SomeClass()
return some_instance.method()
yhab.blah.SomeClass is defined as...
class SomeClass:
def method(self):
return 'hello'
And then I write a test like this...
#mock.patch('yhab.blah.SomeClass')
def test_mock_of_blah_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the real instance, not a mock.
But if I do this...
#mock.patch('yhab.main.SomeClass')
def test_mock_of_main_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the mock, not the real instance and the test passes.
Why is that?
I was thinking that python must make some sort of copy of the class definition when an import happens, but I wrote a test that proves that to not be the case.
The docs say the following, which kind of eludes to this, but it doesn't really say it outright, and IMO doesn't really explain it, especially for a python newb...
Patching a class replaces the class with a MagicMock instance. If the
class is instantiated in the code under test then it will be the
return_value of the mock that will be used.
Do the docs need to be updated to be clear?

After you import SomeClass from yhab.blah, it ends up in the yhab.main namespace, not in the yhab.blah namespace.
Try to use #mock.patch('yhab.main.SomeClass') instead of #mock.patch('yhab.blah.SomeClass').

Related

Python mocking the right class/import

I am trying to implement unittests for my python program. The problem is, that my program is using several imported classes, which I would like to replace by a mocked object/class to verify single functions/methods.
I do not get any errors with my mocked class. But it appears that the mock itself didn't replace the object I wanted to replace.
This is basically my structure:
First the class I want to mock. Might look like that:
class ToMock():
def getSomething(self):
return "something"
The class I want to test looks like this:
from x.y import ToMock
class ClassToTest():
def __init__(self):
self.obj = ToMock()
def returnStuff():
return self.obj.getSomething()
As you can imagine, I want to test the returnStuff method. Therfore I want to mock .getSomething, or better said the whole ToMock object.
The unittest should therefore test the ClassToTest with the mocked ToMock class. I tried several mock.patch variants, but I couldn't get it to run/test properly.
import unittest
from unittest import mock
from a.b import ClassToTest
class TestObject(unittest.TestCase):
def setUp(self):
with mock.patch('x.y.ToMock') as mock_obj:
mock_obj.return_value.getSomething().return_value="mocked return value"
self.test_class = ClassToTest()
result = self.test_class.returnStuff() # This should return now 'mocked return value', I guess?
mock_obj.return_value.getSomething.assert_called_once_with("")
The problem I face is, that the self.test_class.returnStuff() is not "calling" the mocked object, but imports the real class etc. and therefore I am running into timeouts, or similar stuff.
I am sure, that I provide the wrong path for the object which should be mocked. Perhaps someone can hint me into the right direction.
Thanks
-GreNait
The issue is that you are not patching in the correct place. You are patching where the object is defined as opposed to where it is looked up.
a.py
-> Defines ToMock
b.py
-> from a import ToMock
-> some_function/class instantiates ToMock
In your code shown you are patching a.ToMock however you should be patching b.ToMock. That is why it is not running your mock object when testing. You can read more about where to patch here.

Partial patch in Python with mock

How can I use mock.patch on a function, so I have an access to methods .assert_called etc. and simultaneously I can still preserve original functionality of the functions?
Here is example code:
from unittest import mock
def foo(arg):
print(arg)
def tested():
foo('hi')
#mock.patch('__main__.foo')
def test(foo):
tested()
foo.assert_called_once()
test()
I want it to test if the foo function was called just once but I still need it to print hi.
Oh. I have it solved already. I'v just needed to add parameter side_effect to the decorator :-)
Like this:
#mock.patch('__main__.foo', side_effect=foo)
def test(foo):
...

Mocking a function in another file and a class in a second other file

I'm noticing that the class methods are being mocked out properly, but the function is bypassing the mock and running the actual function.
from module1 import myClass
from module2 import my_function
import unittest
from mock import patch
class TestStuff(unittest.TestCase):
#patch('module2.my_function')
#patch('module1.myClass.my_method')
def test_my_function(self, mock_method, mock_function):
test_obj = myClass()
test_obj.my_method()
assert mock_method.called
my_function()
assert mock_function.called
if I print out my_function() and type(my_function) it will not show the mock, but the real function. Does it matter that I'm importing a class then mocking a method, but I'm importing the function directly?
I think I found the issue:
When I'm testing a function, and there's something I want to mock, I should not import it. Importing it causes it to get used, even if I've put the patch decorator.
I think this was general confusion about how mocking/testing works. What I wanted to do was to test a function without actually querying the database. Instead of mocking out the whole function, I could take the line that actually hits the db - query.all() - and make it it's own function, then mock that out.
from module1 import myClass
from module2 import my_function
import unittest
from mock import patch
class TestStuff(unittest.TestCase):
#patch('module2.db_query')
#patch('module1.myClass.my_method')
def test_my_function(self, mock_method, mock_db_query):
test_obj = myClass()
test_obj.my_method()
assert mock_method.called
my_function() # my_function calls db_query(), now mocked out
assert mock_db_query.called
If I had wanted to actually mock out the all of my_function, I could have just not imported it. At least that's how I'm understanding this at the moment.
I ran into a similar issue. Turns out I needed to give it the FULL path to my_function:
#patch('home.myuser.myprojects.mymodule.myfunc')

implement decorator who will be substitute one class with another implementation

What I need is something like that:
def method():
my_var = module.Class1() #actually calling Class1 constructor
...
I need to implement decorator who will be change once class definition with another, like that:
#substitute(module.class1 = new_module.class2)
def method():
my_var = module.Class1() #actually calling new_module.class2 constructor
...
Could you please give me some hints how to do that.
What you are trying to do is called mocking. Use the mock library to do this; the library is part of Python 3.4 and up as unittest.mock.
With mock you can patch the original function while testing only:
try:
from unittest.mock import patch
except ImportError:
# Python < 3.4
from mock import patch
with patch('module.class1') as class1_mock:
mocked_instance = class1_mock.return_value
mocked_instance.method_to_be_called.return_value = 'Test return value'
method()
mocked_instance.method_to_be_called.assert_called_with('Foo', 'bar')
The above mocks out class1 for the duration of the with block, undoing the patch afterwards. The patch replaces module.class1 with a Mock object, which you also have access to as class1_mock. The above example sets up method_to_be_called to return a rigged test return value, and after the test the call signature is verified.

Unit test a method of mocked object

I am trying to get a hang of mocking objects, and seem to by confused by something very basic. I am trying to mock object MyClass and then unit test one of its methods. here is my code:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = mock.Mock()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
In m_my_class.a = 10 I set value of a to to and then in m_my_class.add_two() I add a two, shouldn't I get 12? However, result is:
16 import ipdb;ipdb.set_trace()
---> 17 self.assert_equal(result, 12)
18
ipdb> result
<Mock name='mock.add_two()' id='18379792'>
What am I missing?
Since I am passing the location of the class via decorator to the test method #mock.patch('__main__.MyClass'), shouldn't mocked have all the methods? Because if not, then why does it matter what class we include in the decorator?
Edit:
When I run this code, I still get the same thing.
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
dummy_mock.a = 10
result = dummy_mock.add_two()
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
Result:
ipdb> result
<MagicMock name='MyClass.add_two()' id='38647312'>
Patching the class is almost certainly not what you want to do here. For example, if you changed your test method to this:
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = MyClass(5)
print m_my_class
You will find that rather than getting what you expect:
<__main__.MyClass object at 0x0000000002C53E48>
You'll get this:
<MagicMock name='MyClass()' id='46477888'>
Patching the class in the method means that any time within the method that something tries to instantiate the class it will instead get a mock object. In your particular case, calling MyClass(5) will return the same mock object as calling dummy_mock would. This allows you to set up the mock object so that when you go to test your code the mock object will behave as you want it to.
You really would only use this for dependencies, not the class you are testing. So for example, if your class retrieved data from SQL, you'd patch the SQL class to give your class a mock instead of the normal SQL connection. This allows you to test a class in isolation, without having to worry about externals (like the SQL) getting in the way.
In your example though, you seem to be trying to test a method in isolation. A way you could do that is to extract the function from the method and use that. In code:
def test_add_two(self):
test_mock = mock.Mock()
test_mock.add_two = MyClass.add_two.__func__
test_mock.a = 10
result = test_mock.add_two(test_mock)
self.assert_equal(result, 12)
Normally you wouldn't have to pass in an argument for the self argument, but as here we've pulled out the function you do need to pass in the self argument. If you want you can turn the function into a method bound to your mock object, like this:
import types
...
test_mock.add_two = types.MethodType(MyClass.add_two.__func__, test_mock, test_mock.__class__)
result = test_mock.add_two()
If the function you are testing calls any other methods, you'll need to either do this or mock it out for each of the methods.
I would advise against using this strategy too much, in part because of needing to take care of methods that the tested method calls. Of course, being able to mock out the methods it depends on may be exactly what you're trying to do. In any case, it requires the unit tests to have a pretty deep understanding of how the method works, and not just of what it is supposed to produce. That makes the test very fragile, making it so that you are likely to see the test break far more often than the method you are testing.
Why are you mocking your SUT? This is generally something that you should avoid doing because it introduces the risk that you will not be testing what you think you're testing.
The point of a unit test is to verify the behavior of a unit in complete isolation. One unit typically collaborates with other units in order to provide some useful functionality. Test doubles (mocks, fakes, etc.) are the tools used to achieve this isolation. In a unit test, collaborators of the SUT are replaced with test doubles in order to minimize the number of moving parts.
Your SUT, MyClass, doesn't appear to have any collaborators. As such, no test doubles are necessary to test this unit in isolation (it's already self-contained). This allows you to greatly simplify your unit test:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
def test_add_two(self):
m_my_class = MyClass()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
Edit: The following code demonstrates how a mock object might be used. (Disclaimer: I don't normally work in Python, so my code is probably not very idiomatic. Hopefully the core point still makes sense, though.)
In this example, MyClass adds a value provided by a collaborator, instead of a hardcore value (2).
import mock
import unittest
class MyClass(object):
def __init__(self, a, get_value):
self.a = a
self.get_value = get_value
def add_value(self):
return self.a + self.get_value()
class TestMyClass(unittest.TestCase):
def test_add_value(self):
m_test_value = 42
m_test_a = 10
m_my_class = MyClass()
m_get_test_value = mock.Mock(return_value=m_test_value)
m_my_class.a = test_a
result = m_my_class.add_value()
import ipdb;ipdb.set_trace()
self.assert_equal(result, m_test_a + m_test_value)
if __name__ == '__main__':
unittest.main()
The above example uses a mock object, instead of patching a class. Here is a pretty good explanation of the difference:
Mocking a class: Mock() or patch()?

Categories