Mock class in Python with decorator patch - python

I would like to patch a class in Python in unit testing. The main code is this (mymath.py):
class MyMath:
def my_add(self, a, b):
return a + b
def add_three_and_two():
my_math = MyMath()
return my_math.my_add(3, 2)
The test class is this:
import unittest
from unittest.mock import patch
import mymath
class TestMyMath(unittest.TestCase):
#patch('mymath.MyMath')
def test_add_three_and_two(self, mymath_mock):
mymath_mock.my_add.return_value = 5
result = mymath.add_three_and_two()
mymath_mock.my_add.assert_called_once_with(3, 2)
self.assertEqual(5, result)
unittest.main()
I am getting the following error:
AssertionError: Expected 'my_add' to be called once. Called 0 times.
The last assert would also fail:
AssertionError: 5 != <MagicMock name='MyMath().my_add()' id='3006283127328'>
I would expect that the above test passes. What I did wrong?
UPDATE:
Restrictions:
I would not change the tested part if possible. (I am curious if it is even possible, and this is the point of the question.)
If not possible, then I want the least amount of change in the to be tested part. Especially I want to keep the my_add() function non-static.

Instead of patching the entire class, just patch the function.
class TestMyMath(unittest.TestCase):
#patch.object(mymath.MyMath, 'my_add')
def test_add_three_and_two(self, m):
m.return_value = 5
result = mymath.add_three_and_two()
m.assert_called_once_with(3, 2)
self.assertEqual(5, result)
I think the original problem is that my_math.my_add produces a new mock object every time it is used; you configured one Mock's return_value attribute, but then checked if another Mock instance was called. At the very least, using patch.object ensures you are disturbing your original code as little as possible.

Your code is almost there, some small changes and you'll be okay:
my_add should be a class method since self does not really play a role here.
If my_add is an instance method, then it will be harder to trace the calls, since your test will track the instance signature, not the class sig
Since you are are patching, not stubbing, you should use the "real thing", except when mocking the return value.
Here's what that looks like in your code:
class MyMath:
#classmethod
def my_add(cls, a, b):
return a + b
def add_three_and_two():
return MyMath.my_add(3, 2)
Now, the test:
import unittest
from unittest.mock import patch, MagicMock
import mymath
class TestMyMath(unittest.TestCase):
#patch('mymath.MyMath')
def test_add_three_and_two(self, mymath_mock):
# Mock what `mymath` would return
mymath_mock.my_add.return_value = 5
# We are patching, not stubbing, so use the real thing
result = mymath.add_three_and_two()
mymath.MyMath.my_add.assert_called_once_with(3, 2)
self.assertEqual(5, result)
unittest.main()
This should now work.

Related

Mocking dependencies

I am Python newbie and trying to understand how to mock methods in UTs.
Here is my Test
test_module2.py
from module2 import A
import unittest
from unittest.mock import patch, MagicMock
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, a):
a.simpleFun = MagicMock(return_value=3)
testA = A()
testA.fun()
assert a.simpleFun.called
and I want to check that dependent SimpleModuleClass was mocked and invoked
module2.py
from simple_module import SimpleModuleClass
class A:
def fun(self):
print('I am from A class')
thing = SimpleModuleClass()
thing.simpleFun()
return -1
simple_module.py
class SimpleModuleClass:
def simpleFun(self):
print("I am from SimpleModuleClass")
return 0
I get AssertionError. Could you help me understand how to fix this?
a.simpleFun = MagicMock(return_value=3)
This line is only modifying the method of your mock object a (which you really should rename simpleModuleMock, since it's a mock of a SimpleModule class and not an A). It doesn't mock every instance of SimpleModule everywhere in your code, hence why an instance of SimpleModule is instantiated in A.fun() and not an instance of a mock of SimpleModule.
I would use dependency injection and pass an instance of SimpleModule to A.fun() instead of instantiating it inside of it, so that you can pass a mock. You could also make thing a public variable like so:
test_module2.py:
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, simpleModuleMock):
simpleModuleMock.simpleFun = MagicMock(return_value=3)
testA = A()
A.thing = simpleModuleMock
assert(testA.fun() == -1)
# assert simpleModule.simpleFun.called
assert isinstance(simpleModuleMock.simpleFun, MagicMock)
module2.py:
class A:
thing = SimpleModuleClass()
def fun(self):
print('I am from A class')
self.thing.simpleFun()
return -1
Note that there may exist better solutions with Python, but if there are, 1. I don't know of them, and 2. I doubt they're good practice.

How to mock using sys.modules and with mock.patch (Python interference on static functions)

So I've this code that mocks two times, the first time by mocking imports with:
sys.modules['random'] = MagicMock()
The second time happens inside the unittest of a function that used that import, for example a function that used random
The tests. py is:
import sys
import unittest
from unittest import mock
from unittest.mock import MagicMock
import foo
sys.modules['random'] = MagicMock()
class test_foo(unittest.TestCase):
def test_method(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'Should be 2')
def test_staticmethod(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'should be 2')
The original file Foo.py is:
import random
class FooClass:
def __init__(self,arg):
self.arg = arg
def method(self):
print(random.choice)
return random.choice([1,2,3])
#staticmethod
def staticmethod():
print(random.choice)
random.choice([1,2,3])
The two mocks contrarrest each other, and the mocking of random doesn't happen.
When it prints random it actually prints:
<<bound method Random.choice of <random.Random object at 0x7fe688028018>>
I want that to print a MagicMock.
Can someone help me understand what's happening? Why are they contrarresting each other?
You don't need to update the module source with sys.modules['random'] = MagicMock() without this line it works fine <MagicMock name='choice' id='...'>. patch already does all the work for the isolated temporary updating the method. See more explanation in the docs - Where to patch

Test instance of class that mocked method is called from in Python

I am mocking out a method of a class and want to test the instance of the class that the method was called from to test that the creation part of my function works as expected.
In my particular case do_stuff tries to write bar_instance to an Excel File and I don't want that to happen i.e.
def create_instance(*args):
return Bar(*args)
class Bar():
def __init__(self, *args):
self.args = args
def do_stuff(self):
pass
def foo(*args):
bar_instance = create_instance(*args)
bar_instance.do_stuff()
Then in a testing file
from unittest import TestCase
from unittest.mock import patch
from path.to.file import foo
class TestFoo(TestCase):
#patch('path.to.file.Bar.do_stuff')
def test_foo(self, mock_do_stuff):
test_args = [1]
_ = foo(*test_args)
# Test here the instance of `Bar` that `mock_do_stuff` was called from
# Something like
actual_args = list(bar_instance.args)
self.assertEqual(test_args, actual_args)
I put a break in the test function after foo(*test_args) is run but can't see any way from the mocked method of accessing the instance of Bar it was called from and am a bit stuck. I don't want to mock out Bar further up the code as I want to make sure the correct instance of Bar is being created.
In your code example, there are three things that might need testing: function create_instance, class Bar and function foo. I understand your test code such that you want to ensure that function foo calls do_stuff on the instance returned by create_instance.
Since the original create_instance function has control over the created instance, a solution of your problem is to mock create_instance such that your test gains control of the object that is handed over to foo:
import unittest
from unittest import TestCase
from unittest.mock import patch, MagicMock
from SO_60624698 import foo
class TestFoo(TestCase):
#patch('SO_60624698.create_instance')
def test_foo_calls_do_stuff_on_proper_instance (
self, create_instance_mock ):
# Setup
Bar_mock = MagicMock()
create_instance_mock.return_value = Bar_mock
# Exercise
foo(1, 2, 3) # args are irrelevant
# Verify
Bar_mock.do_stuff.assert_called()
if __name__ == '__main__':
unittest.main()
In addition, you might also want to test if foo passes the arguments correctly to create_instance. This could be implemented as a separate test:
...
#patch('SO_60624698.create_instance')
def test_foo_passes_arguments_to_create_instance (
self, create_instance_mock ):
# Setup
create_instance_mock.return_value = MagicMock()
# Exercise
foo(1, 22, 333)
# Verify
create_instance_mock.assert_called_with(1, 22, 333)
And, certainly, to complete the whole test of the object generation, you could test create_instance directly, by calling it and checking on the returned instance of Bar if it has used its arguments correctly for the construction of the Bar instance.
As patch returns an instance of Mock (or actually MagicMock, but it inherits the relevant methods from its base - Mock), you have the assert_called_with method available, which should do the trick.
Note that this method is sensitive to args/kwargs - you have to assert the exact same call.
Another note: it might be a better practice to use patch.object instead of patch here

Monkey patch a python function - issue

I'm in trouble replacing a python function from a different module with a TestClass
I'm trying to test a part of my code that contains the function in a module; more in details I would like monkey patch this function.
So, the situation is similar to the following:
Function in the module
def function_in_module():
# do some stuff
return 'ok'
Part of my code that I would like testing
from dir_1.dir_2.dir_3.module_name import function_in_module
class ExampleClass():
def __init__(self):
# do some stuff
self.var_x = function_in_module()
# do some stuff again
Test class
from dir_1.dir_2.dir_3 import module_name
class TestClass(TestCase):
de_monkey = {}
mp = None
def setUp(self):
# save original one
self.de_monkey['function_in_module'] = module_name.function_in_module()
if self.mp is None:
self.mp = MP()
def tearDown(self):
# rollback at the end
module_name.function_in_module = self.de_monkey['function_in_module']
def test_string(self):
module_name.function_in_module = self.mp.monkey_function_in_module
test_obj = ExampleClass()
self.assertEqual(test_obj.var_x, 'not ok')
class MP(object):
#staticmethod
def monkey_function_in_module(self):
return 'not ok'
As the assert statement shows, the expected result is 'not ok', but the result is 'ok'.
I have debugged about this and seems that the different way to call the functions is the reason because this monkey patch doesn't work.
In fact, if I try to call the function in ExampleClass in this way
self.var_x = module_name.function_in_module()
works correctly.
What am I missing? maybe it's a banality but it's driving me crazy
Thank you in advance
Your code under test imports function_in_module and references it directly. Changing the value of module_name.function_in_module has no effect on the code.
You should replace the function directly in the module that contains the code under test, not in the source module.
Note that your life would be easier if you used the mock library, although the question of where to patch would still be the same.

Mocking a class: Mock() or patch()?

I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).
Method one: Just create a mock object and use that. The code looks like:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Method two: Use patch to create a mock. The code looks like:
#patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Both methods do the same thing. I am unsure of the differences.
Could anyone enlighten me?
mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:
>>> class MyClass(object):
... def __init__(self):
... print 'Created MyClass#{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created MyClass#4299548304
>>>
>>> #mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass#4300234128
<__main__.MyClass object at 0x100505d90>
patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.
mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.
I've got a YouTube video on this.
Short answer: Use mock when you're passing in the thing that you want mocked, and patch if you're not. Of the two, mock is strongly preferred because it means you're writing code with proper dependency injection.
Silly example:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)
Key points which explain difference and provide guidance upon working with unittest.mock
Use Mock if you want to replace some interface elements(passing args) of the object under test
Use patch if you want to replace internal call to some objects and imported modules of the object under test
Always provide spec from the object you are mocking
With patch you can always provide autospec
With Mock you can provide spec
Instead of Mock, you can use create_autospec, which intended to create Mock objects with specification.
In the question above the right answer would be to use Mock, or to be more precise create_autospec (because it will add spec to the mock methods of the class you are mocking), the defined spec on the mock will be helpful in case of an attempt to call method of the class which doesn't exists ( regardless signature), please see some
from unittest import TestCase
from unittest.mock import Mock, create_autospec, patch
class MyClass:
#staticmethod
def method(foo, bar):
print(foo)
def something(some_class: MyClass):
arg = 1
# Would fail becuase of wrong parameters passed to methd.
return some_class.method(arg)
def second(some_class: MyClass):
arg = 1
return some_class.unexisted_method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_autospec(self):
mock = create_autospec(MyClass)
mock.method.return_value = True
# Fails because of signature misuse.
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_something(self):
mock = Mock() # Note that Mock(spec=MyClass) will also pass, because signatures of mock don't have spec.
mock.method.return_value = True
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
class TestSecondTestCase(TestCase):
def test_second_with_autospec(self):
mock = Mock(spec=MyClass)
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second(self):
mock = Mock()
mock.unexisted_method.return_value = True
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
The test cases with defined spec used fail because methods called from something and second functions aren't complaint with MyClass, which means - they catch bugs, whereas default Mock will display.
As a side note there is one more option: use patch.object to mock just the class method which is called with.
The good use cases for patch would be the case when the class is used as inner part of function:
def something():
arg = 1
return MyClass.method(arg)
Then you will want to use patch as a decorator to mock the MyClass.

Categories

Resources