I have been trying to test a function that calls another function with some parameters. I am trying to mock the latest so that it won't actually run and instead executes a mock function that returns some mock values.
What I have -simplified- looks like that:
def function_to_test():
a = 2
b = 3
c = 4
results = second_function(a, b, c)
return results
Then the function that I am trying to mock looks like that:
def second_function(a, b , c):
a = b + c
return a
Both function_to_test
and second_function
belong to the class Example
.
I am using unittest
for my tests and I cannot switch to pytest unfortunatelly, so no pytest options are helpful.
What I have managed to do so far with the test is:
@patch('rootfolder.subfolder.filename.Example.second_function', autospec=True)
def test_function_to_test(self, get_content_mock):
get_content_mock.return_value = mocked_second_function()
res = function_to_test()
self.assertEqual(res, 10)
As you can see I am trying to use a mocked function instead the actual second_function
that looks like that:
def mocked_second_function(a, b, c):
# using a, b, c for other actions
# for the question I will just print them but they are actually needed
print(f"{a}, {b}, {c}")
return 10
The problem is that when I set the get_content_mock.return_value = mocked_second_function()
.
I am required to pass the parameters, but in my actual problem, these parameters are being generated at the function_to_test
so I have no way of knowing them beforehand.
I read many related questions and documentation but I cannot seem to find something that helps my problem. Any help or even a different approach would be helpful.
Using the unittest library there is assert_called_with
. If this is used with the MagicMock
capability then you can test the first_function
without the actual second_function
being ran but test that it has been called with the correct parameters.
Here is an example test with the correct and the wrong parameters:
import unittest
from unittest.mock import MagicMock
class Example:
def first_function(self):
a = 2
b = 3
c = 4
results = self.second_function(a, b, c)
return results
def second_function(self, a, b , c):
a = b + c
return a
class TestMockSecondMethod(unittest.TestCase):
def test_func_dut_pass(self):
example = Example()
example.second_function = MagicMock(return_value=7)
result = example.first_function()
example.second_function.assert_called_with(2, 3, 4)
self.assertEqual(7, result)
def test_func_dut_fail(self):
example = Example()
example.second_function = MagicMock(return_value=7)
result = example.first_function()
example.second_function.assert_called_with(1, 3, 4)
self.assertEqual(7, result)
if __name__ == '__main__':
unittest.main()
This gave the following output:
$ python3.6 -m unittest --v so_unittest_mock.py
test_func_dut_fail (so_unittest_mock.TestMockSecondMethod) ... FAIL
test_func_dut_pass (so_unittest_mock.TestMockSecondMethod) ... ok
======================================================================
FAIL: test_func_dut_fail (so_unittest_mock.TestMockSecondMethod)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/user1/so_unittest_mock.py", line 28, in test_func_dut_fail
example.second_function.assert_called_with(1, 3, 4)
File "/usr/lib/python3.6/unittest/mock.py", line 814, in assert_called_with
raise AssertionError(_error_message()) from cause
AssertionError: Expected call: mock(1, 3, 4)
Actual call: mock(2, 3, 4)
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=1)