2

A global variable can be easily mocked following these answers. Great. However, this does not work when trying to mock a variable in a script that you call with subprocess.call() in a test with Pytest.

Here is my simplified script in a file called so_script.py:

import argparse

INCREMENTOR = 4


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('input_nr', type=int, help='An int to increment')
    args = parser.parse_args()

    with open('test.txt', 'w+') as f:
        f.write(str(args.input_nr + INCREMENTOR))

Now, say I want to mock the value of INCREMENTOR in my tests to be 1. If I do this:

from subprocess import call
from unittest import mock

def test_increments_with_1():
    with mock.patch('so_script.INCREMENTOR', 1):
        call(['python', 'so_script.py', '3'])
    with open('test.txt', 'r+') as f:
        assert f.read() == '4'

The test will fail, because the value of INCREMENTOR remains 4, even though I tried to patch it to 1. So what gets written to the file is 7 instead of 4.

So my question is: how do I mock the INCREMENTOR global variable in my so_script.py file so that, when calling subprocess.call() on it, it remains mocked?

Chris
  • 1,173
  • 11
  • 19
  • Mock is used with language resources (objects). In this case, you are using a operation system resource. When you call a sub process from so, by definition you are not using a Python resource, but a so resource and assigning result, or sometimes stdout, to Python object. That's why you can't do what you want. – Mauro Baraldi Nov 23 '18 at 20:13

1 Answers1

0

Because the so_script.py script and pytest are executed in different processes, one cannot mock objects in so_script.py while the latter is being called as a different process in tests.

The best solution I found was to put everything from the if __name__ == '__main__: block in a function and test that function with Pytest, mocking whatever I needed to mock. And, to have 100% test coverage (which was my initial intent with calling the script as a subprocess), I applied this solution.

So I dropped using subprocess.call() in my tests and wrote an init() function checking if __name__ == '__main__:, and then mocked __name__ in the tests to test the function, just as the article advises to do. This got me 100% test coverage and full mocking capabilities.

Chris
  • 1,173
  • 11
  • 19