2

Trying to understand unittest.mock more, but not sure why its running the program twice. For simplicity, consider the code below in a file test.py:

from unittest.mock import patch

class T():
    def __init__(self):
        self.setup()

    def setup(self):
        mock_testing = patch('test.testing').start()
        mock_testing.return_value = "new testing"

def testing():
    return "testing"

print("Hello")

t = T()

print("Setting up")

if testing() == "testing":
    print("old style")
elif testing() == "new testing":
    print("new style")

When I run the script with python test.py, I get:

Hello
Hello
Setting up
new style
Setting up
old style

Why does it run the code twice? And even if it does run it twice, how come 'hello' is printed back to back, should it be printed like:

Hello
Setting up
new style
Hello
Setting up
old style

Also how can I make it so that it just runs the code once, with the mock value of 'new testing'?

Dan Getz
  • 8,774
  • 6
  • 30
  • 64
user1179317
  • 2,693
  • 3
  • 34
  • 62

1 Answers1

3

This is because the script is loaded as the module __main__ first, and yet you're calling patch with test.testing, so patch will import test.py again as the test module. Since patch is called before "Setting up" is printed, the loading of the test module, as well as the printing of "Hello" by both the __main__ module and the test module, will be done before "Setting up" is printed by the __main__ module.

If you add __name__ to the arguments for print, you'll more easily see what's going on:

from unittest.mock import patch

class T():
    def __init__(self):
        self.setup()

    def setup(self):
        mock_testing = patch('test.testing').start()
        mock_testing.return_value = "new testing"

def testing():
    return "testing"

print(__name__, "Hello")

t = T()

print(__name__, "Setting up")

if testing() == "testing":
    print(__name__, "old style")
elif testing() == "new testing":
    print(__name__, "new style")

This outputs:

__main__ Hello
test Hello
test Setting up
test new style
__main__ Setting up
__main__ old style

To avoid this, you should patch __main__.testing instead, so that after the modification, the above code will output:

__main__ Hello
__main__ Setting up
__main__ new style
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    That makes a lot of sense. Didnt realize patch was importing the module again. Thanks a lot for the explanation! – user1179317 Nov 14 '19 at 00:49
  • Importing the same module with two different names is strongly discourage and can lead to loads of weird errors. In fact code is imported twice, global variables exist in two different name spaces with potentially two different values. patch imports the module only again if you import it with a different name. In other words if you execute a script as `__main__`, then you should not patch `"test.testing"` you should have mocked `"__main__.testing"` instead. – gelonida Nov 17 '19 at 00:26