我目前正在写一篇关于在Python中为单元测试打补丁的文章,我很困惑为什么以下工作。当我在该目录中执行pytest
时,测试成功,尽管我的系统时间不是 1990 年。
我以为datetime.datetime = NewDate
只会在test_example.py
内产生影响.我想我需要更好地了解 Python 存储名称/指向导入模块的指针的位置。有人可以解释一下吗?
example.py
# Core Library modules
import datetime
def generate_filename():
return f"{datetime.datetime.now():%Y-%m-%d}.png"
test_example.py
# Core Library modules
import datetime
from unittest import mock
# First party modules
from mock_example import generate_filename
class NewDate(datetime.datetime):
@classmethod
def now(cls):
return cls(1990, 4, 28)
def test_generate_filename():
datetime.datetime = NewDate
assert generate_filename() == "1990-04-28.png"
在导入from mock_example import generate_filename
的行上,执行import datetime
,因此datetime.datetime
的值在datetime.datetime = NewDate
被覆盖,因为它是在导入后执行的。在同一程序上发生的任何全局变量(包括导入(的所有修改都会影响程序中的所有位置,无论它们位于不同的文件中。
您实际上是在访问两个文件上的相同"变量"。如果您像from datetime import datetime
一样导入它,则不会发生这种情况(有关此内容的更多信息,请参阅@Vishal Singh答案(
一旦你修补了test_generate_filename
里面的datetime.datetime
模块,你就需要注意
import a
或import a.b
(并像a.method
或a.b.method
一样使用它(from a import b
(如果在调用test_generate_filename
之前导入,这将留下 b 的未修补引用,如果在该模块中使用,将为您提供未修补的内容(
在您的情况下,您像import datetime
一样导入它,因此没有旧的引用,并且您已经修补了模块,因此将来在任何文件中使用datetime.datetime.now()
都会返回修补的内容,即 90 年代的日期。
如果您尝试在example.py
文件中导入日期时间(如from datetime import datetime
(,则断言将失败。