Have you tried to patch a function call in your unit test and wondering why the hell patching is not working, value I'm returning from the patched function is not the value being used in the function call. Well, may be you are not patching at the right place.
I saw this problem at work. I'll try to explain with a simple example.
you have a module module_a which has a function greet. There is another module module_b which uses this function from module_a in another function - sayHi. When we write test case for module_b's sayHi, we want to patch function call to module_a's greet method.
module_a.py
module_b.py
test_mod_b.py
Here, we are writing test case for module_b's sayHi function and want to patch module_a's greet function. On executing this test case, it fails.
PS D:\development\test> python -m unittest
F
======================================================================
FAIL: test1 (test_ut.mocktest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\development\test\test_ut.py", line 8, in test1
self.assertEqual(res,'how are you')
AssertionError: 'hello world' != 'how are you'
- hello world
+ how are you
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
Reason being - we are patching module_a's greet function. when module_b is loaded, it first loads module_a.greet and then this function is already available in module_b. So the call will not be module_a.greet instead it will be just greet from module_b. Hence we need to patch module_b.greet .
modified unit test
unit test result -
PS D:\development\test> python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Visual studio code showing during module_b load that greet is available as a local variable and no longer a call to module_a.greet
on the other hand, if you only import module_a in module_b then when calling greet function, you will have to refer to it as module_a.greet . In that case, this approach will not work and you need to patch module_a.greet in your unit test since you will be accessing greet function using module_a reference .
modified module_b(importing module_a and not the greet function)
updated unit test
PS D:\development\test> python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
That's it on unit testing for now .
I saw this problem at work. I'll try to explain with a simple example.
you have a module module_a which has a function greet. There is another module module_b which uses this function from module_a in another function - sayHi. When we write test case for module_b's sayHi, we want to patch function call to module_a's greet method.
module_a.py
def greet():
""" returns sum of two numbers"""
return 'hello world'
module_b.py
from module_a import greet
class myClass():
def sayHi(self):
return greet()
if __name__ == '__main__':
res = myClass().sayHi()
print(res)
test_mod_b.py
import unittest
from unittest.mock import patch
from module_b import myClass
class mocktest(unittest.TestCase):
def test1(self):
with patch('module_a.greet',return_value='how are you'):
res = myClass().sayHi()
self.assertEqual(res,'how are you')
if __name__ == '__main__':
unittest.main()
Here, we are writing test case for module_b's sayHi function and want to patch module_a's greet function. On executing this test case, it fails.
PS D:\development\test> python -m unittest
F
======================================================================
FAIL: test1 (test_ut.mocktest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\development\test\test_ut.py", line 8, in test1
self.assertEqual(res,'how are you')
AssertionError: 'hello world' != 'how are you'
- hello world
+ how are you
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
Reason being - we are patching module_a's greet function. when module_b is loaded, it first loads module_a.greet and then this function is already available in module_b. So the call will not be module_a.greet instead it will be just greet from module_b. Hence we need to patch module_b.greet .
modified unit test
import unittest
from unittest.mock import patch
from module_b import myClass
class mocktest(unittest.TestCase):
def test1(self):
with patch('module_b.greet',return_value='how are you'):
res = myClass().sayHi()
self.assertEqual(res,'how are you')
if __name__ == '__main__':
unittest.main()
unit test result -
PS D:\development\test> python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Visual studio code showing during module_b load that greet is available as a local variable and no longer a call to module_a.greet
on the other hand, if you only import module_a in module_b then when calling greet function, you will have to refer to it as module_a.greet . In that case, this approach will not work and you need to patch module_a.greet in your unit test since you will be accessing greet function using module_a reference .
modified module_b(importing module_a and not the greet function)
import module_a
class myClass():
def sayHi(self):
return module_a.greet()
if __name__ == '__main__':
res = myClass().sayHi()
print(res)
updated unit test
import unittest
from unittest.mock import patch
from module_b import myClass
class mocktest(unittest.TestCase):
def test1(self):
with patch('module_a.greet',return_value='how are you'):
res = myClass().sayHi()
self.assertEqual(res,'how are you')
if __name__ == '__main__':
unittest.main()
PS D:\development\test> python -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
That's it on unit testing for now .
Comments
Post a Comment