Python单元测试模拟运行程序两次

Python单元测试模拟运行程序两次,python,python-unittest,python-unittest.mock,Python,Python Unittest,Python Unittest.mock,试图了解unittest.mock更多,但不确定为什么要运行两次程序。为简单起见,请考虑以下文件中的代码 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.re

试图了解unittest.mock更多,但不确定为什么要运行两次程序。为简单起见,请考虑以下文件中的代码<代码> 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")
当我使用
python test.py
运行脚本时,我得到:

Hello
Hello
Setting up
new style
Setting up
old style
为什么它要运行两次代码?即使它确实运行了两次,为什么“hello”会背靠背打印,应该像这样打印:

Hello
Setting up
new style
Hello
Setting up
old style

另外,我如何使它只运行代码一次,模拟值为“new testing”?

这是因为脚本首先作为模块
\uuuu main\uuuu
加载,而您正在使用
测试调用
补丁,因此,
patch
将再次导入
test.py
作为
test
模块。由于在打印
“设置”
之前调用了
补丁
,因此
测试
模块的加载以及
模块和
测试
模块对
你好
的打印将在
模块打印
设置
之前完成

如果将
\uuu name\uuu
添加到
打印
的参数中,您将更容易看到发生了什么:

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")
这将产生:

__main__ Hello
test Hello
test Setting up
test new style
__main__ Setting up
__main__ old style
为了避免这种情况,您应该改为修补
\uuuuu main\uuuu.testing
,以便在修改后,上述代码将输出:

__main__ Hello
__main__ Setting up
__main__ new style

我以python test.py的形式运行它。。它确实给出了非常有意义的结果。未意识到修补程序正在再次导入模块。谢谢你的解释!强烈反对使用两个不同的名称导入同一模块,这可能会导致大量奇怪的错误。事实上,代码被导入两次,全局变量存在于两个不同的名称空间中,可能有两个不同的值。仅当您使用其他名称导入模块时,修补程序才会再次导入该模块。换句话说,如果您以
\uuuuu main\uuuuu
的形式执行脚本,那么您不应该修补
“test.testing”
您应该模拟
“\uuuuuu main\uuuuuu.testing”