Skip to content
Advertisement

Integration test for decorated function

I have a problem in writing integration test for some function that calls other function which is decorated. Suppose the following definitions:

# myproj.py

import logging


def catch_every_error(func):
    logger = logging.getLogger("mylogger")

    def wrapper(*args, **kwargs):
        try:
            result = func(*args, **kwargs)
        except Exception as e:
            logger.exception("")
        else:
            return result

    return wrapper


@catch_every_error
def problematic_func():
    pass


def func_under_test():
    # doing something very critical here
    # ....

    problematic_func()

I need to write test to ensure that any exception raised inside problematic_func will not be propagated to func_under_test. For this reason, I used mocking like below:

import unittest
from unittest.mock import patch

from myproj import func_under_test


class MyTestCase(unittest.TestCase):
    @patch("myproj.problematic_func")
    def test_no_exception_raises(self, mock_problematic_func):
        mock_problematic_func.side_effect = Exception("Boom")

        try:
            func_under_test()
        except Exception:
            self.fail(
                "exception in problematic function propagated to 'func_under_test'"
            )


if __name__ == "__main__":
    unittest.main()

Problem is that I can’t pass this test. Patching problematic_func caused removal of decorator applied to that function and exceptions are not catched. For applying decorator manually, I tried:

    mock_problematic_func = catch_every_error(mock_problematic_func)

This also doesn’t result with successful test passing. Exception is still raised when calling func_under_test in my test case. How should I test that any exception raised inside problematic_func doesn’t cause failure in func_under_test?

Note: Please don’t suggest writing test for catch_every_error decorator. I am trying to fulfill integration test for func_under_test.

Advertisement

Answer

Working version of the test above is like below:

import unittest
from unittest.mock import patch

import myproj


class MyTestCase(unittest.TestCase):
    @patch("myproj.problematic_func")
    def test_no_exception_raises(self, mock_problematic_func):
        mock_problematic_func.side_effect = Exception("Boom")
        myproj.problematic_func = myproj.catch_every_error(mock_problematic_func)

        try:
            myproj.func_under_test()
        except Exception:
            self.fail(
                "exception in problematic function propagated to 'func_under_test'"
            )


if __name__ == "__main__":
    unittest.main()

Previously, I tried (with no successful result):

from myproj import catch_every_error

mock_problematic_func = catch_every_error(mock_problematic_func)

For some reason (I don’t know exactly), importing function with from statement and decorating manually didn’t work. Although importing whole module (import myproj) and manually decorating with resetting attribute (myproj.problematic_func =) worked.

Advertisement