I have 2 functions and the other one is called only when the parameter passed is True.
def func1(para1 = True):
// Some lines of code
if para1 == True:
func2()
def func2():
// Some lines of code
Now, I'm trying to create a unittest that checks whether the nested function func2 is being called(When parameter passed to func1 is true). I checked online and found something related to Mock() but did not understand how to use for this particular test case. How can I proceed with this?
example.py:
def func1(para1=True):
if para1 == True:
func2()
def func2():
pass
test_example.py:
from unittest import TestCase
import unittest
from unittest.mock import patch
from example import func1
class TestExample(TestCase):
#patch('example.func2')
def test_func1__should_call_func2(self, mock_func2):
func1()
mock_func2.assert_called_once()
#patch('example.func2')
def test_func1__should_not_call_func2(self, mock_func2):
func1(False)
mock_func2.assert_not_called()
if __name__ == '__main__':
unittest.main()
Test result:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Related
I known how I can test if an injected object was called with a specific argument. But in my case the injected object will create an object that object will create another object and I want to test if that last object was called with the right argument.
in the example below the question would be if c.dirve was called with 100 as argument:
class car:
def drive(self, distance):
print("so fast")
class car_shop:
def buy_car(self):
return car()
class shop_shop:
def buy_shop(self):
return car_shop()
class processor:
def __init__(self, sshop):
self.sshop = sshop
def run(self):
cshop = self.sshop.buy_shop()
c = cshop.buy_car()
c.drive(100)
def main():
sshop = shop_shop()
proc = processor(sshop)
proc.run()
if __name__ == "__main__":
main()
is there a way to test that?
Since this was requested here my approach for testing these objects:
import pytest
from unittest.mock import Mock
from object_returns_object_test_for_arguments import processor, shop_shop
#pytest.fixture
def mock_shop_shop():
return Mock(spec=shop_shop)
def test_processor_car_called_with_100(mock_shop_shop):
proc = processor(mock_shop_shop)
proc.run()
assert mock_shop_shop.car_shop.car.drive.assert_called_once_with(100)
assert mock_shop_shop.car_shop.car.drive.call_count == 1
If using just the code shown in the question, you only have to mock car.drive. This could be done for example this way:
from unittest import mock
from object_returns_object_test_for_arguments import processor, shop_shop
#mock.patch('object_returns_object_test_for_arguments.car.drive')
def test_processor_car_called_with_100(drive_mock):
proc = processor(shop_shop())
proc.run()
drive_mock.assert_called_once_with(100)
As I don't know your real code, you may have to mock more stuff.
As an aside: class names in Python are written upper-case, camelcase-style by default.
I want to replace this boilerplate:
def Foo():
pass
if __name__ == "__main__":
run_unit_test(Foo)
With this:
#test_if_main
def Foo():
pass
Is it possible?
No, Because the Foo test function is defined without being called anywhere.
But you can try:
def test_if_main(test_func):
if __name__ == "__main__":
run_unit_test(test_func)
#test_if_main
def Foo():
pass
# utils.py
import inspect
def test_if_main(f):
caller = inspect.stack()[1]
mod = inspect.getmodule(caller[0])
if mod.__name__ == "__main__":
print('running unit tests...')
return f
# Foo.py
from utils import test_if_main
#test_if_main
def Foo():
print(42)
# handled by #test_if_main
# if __name__ == "__main__":
# print("do unit tests here...")
# Bar.py
from Foo import Foo
Foo()
python3 Foo.py prints do unit tests here...
python3 Bar.py prints 42
I have a situation which i could not find on stack-overflow:
some_module.py:
class SomeModule():
def a(): pass
def b(): pass
def c(): pass
#classmethod
def bring_them_altogether(cls):
cls.a()
cls.b()
cls.c()
I am writing a unittest and would like to test the method bring_them_altogether() by determining that methods a(), b() & c() are all called once.
In my testcase i have this:
test.py:
#patch('<...>.some_module.SomeModule', autospec=True)
def test_bring_them_altogether(self, mock_class):
mock_class.bring_them_altogether()
self.assertTrue(mock_class.called) # Returns me False
I want to know how to write a proper test case for bring_them_altogether() as i seem to be having some issues getting the output i want.
On that note, I want to know how to determine that a mocked-method has been called X - number of times.
Thank you for pointing me in the right direction
You should use patch.object to patch a, b, c methods of SomeModule class. Check if they are called or not after executing the bring_them_altogether method.
E.g.
some_module.py:
class SomeModule():
def a(): pass
def b(): pass
def c(): pass
#classmethod
def bring_them_altogether(cls):
cls.a()
cls.b()
cls.c()
test_some_module.py:
import unittest
from unittest.mock import patch
from some_module import SomeModule
class TestSomeModule(unittest.TestCase):
#patch.object(SomeModule, 'c')
#patch.object(SomeModule, 'b')
#patch.object(SomeModule, 'a')
def test_bring_them_altogether(self, mock_a, mock_b, mock_c):
SomeModule.bring_them_altogether()
mock_a.assert_called_once()
mock_b.assert_called_once()
mock_c.assert_called_once()
if __name__ == '__main__':
unittest.main()
unit test result with coverage report:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
------------------------------------------------------------------------------
src/stackoverflow/58950420/some_module.py 8 0 100%
src/stackoverflow/58950420/test_some_module.py 13 0 100%
------------------------------------------------------------------------------
TOTAL 21 0 100%
My approach to mock testing functions looks like this:
from unittest import mock, TestCase
from main import my_function
def my_mock(s):
if s == 'hello':
return 'goodbye'
return my_function(s)
class TestMyFunction(TestCase):
#mock.patch('my_function', side_effect=MyMock.my_mock)
def test_my_function(self, mock_get):
s = 'hello'
self.assertEqual('goodbye', my_function(s))
This works. But if I have multiple tests, where my_mock_1 patches test_my_function_1 and my_mock_2 patches test_my_function_2 and so on, the mock definitions are very far from the test definitions and the code becomes hard to read.
Is there a way to get the mock definition closer to the tests they belong to?
What I tried was
class TestMyFunction(TestCase):
#staticmethod
def my_mock_1(s):
...
#mock.patch('my_function', side_effect=my_mock_1)
def test_my_function_1(self, mock_get):
...
#staticmethod
def my_mock_2(s):
...
#mock.patch('my_function', side_effect=my_mock_2)
def test_my_function_2(self, mock_get):
...
...
But this fails with the exception
TypeError: 'staticmethod' object is not an iterator.
I want to create the test case for check the same function in many files. Each file has the same function name but different algorithm.
I tried to create a loop for test each file in unit-test but it didnt't work.
__import__('name') will return a module. So here we can find a solution:
lib1.py, lib2.py, lib3.py:
def func():
return 123
test.py:
import unittest
class TestFoo(unittest.TestCase):
def test_bar(self):
for name in ['lib1','lib2','lib3']:
result=__import__(name).func()
self.assertEqual(result, 123)
if __name__ == '__main__':
unittest.main()