2

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.

Flora Biletsiou
  • 309
  • 3
  • 6
  • 17

1 Answers1

1

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)
ukBaz
  • 6,985
  • 2
  • 8
  • 31