Thursday 12 November 2020

Avoiding running top-level module code in unit test

I am attempting to unit test some Python 3 code that imports a module. Unfortunately, the way the module is written, simply importing it has unpleasant side effects, which are not important for the tests. I'm trying to use unitest.mock.patch to get around it, but not having much luck.

Here is the structure of an illustrative sample:

.
└── work
    ├── __init__.py
    ├── test_work.py
    ├── work.py
    └── work_caller.py

__init__.py is an empty file

work.py

import os


def work_on():
    path = os.getcwd()
    print(f"Working on {path}")
    return path

def unpleasant_side_effect():
    print("I am an unpleasant side effect of importing this module")

# Note that this is called simply by importing this file
unpleasant_side_effect()

work_caller.py

from work.work import work_on

class WorkCaller:
    def call_work(self):
        # Do important stuff that I want to test here

        # This call I don't care about in the test, but it needs to be called
        work_on()

test_work.py

from unittest import TestCase, mock

from work.work_caller import WorkCaller


class TestWorkMockingModule(TestCase):
    def test_workcaller(self):
        with mock.patch("work.work.unpleasant_side_effect") as mocked_function:
            sut = WorkCaller()
            sut.call_work()

In work_caller.py I only want to test the beginning code, not the call to work_on(). When I run the test, I get the following output:

paul-> python -m unittest
I am an unpleasant side effect of importing this module
Working on /Users/paul/src/patch-test
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

I was expecting that the line I am an unpleasant side effect of importing this module would not be printed because the function unpleasant_side_effect would be mocked. Where might I be going wrong?



from Avoiding running top-level module code in unit test

No comments:

Post a Comment