为什么 pytest 模拟程序全局修补模块方法(取决于模块导入)?

问题描述 投票:0回答:0

问题:

为了测试,我想在我的主模块中修补

time.sleep
(并声明它的调用),without在子模块中修补它。 但是,在我的模块中导入
time
并在我的主模块(
time.sleep
)中修补
mocker.patch("main.time.sleep")
也会在
所有
子模块中模拟time.sleep(场景A)。
同时,从
sleep
中导入
time
并在我的主模块中修补
sleep
(
mocker.patch("main.sleep")
) 模拟
sleep
only 在主模块中(场景 B,期望的结果)。

问题

为什么?为什么进口会有所不同?为什么

time.sleep
首先在全球范围内被嘲笑?不应该只在它被查找的地方被嘲笑吗?

想法

根据单元测试Where-To-Patch-Article“patch() 的工作原理是(暂时)将名称指向的对象更改为另一个名称”。
→ 那么,

sleep
中的方法
time
应该被两种场景中的所有模块替换吗?

此外,“你在查找对象的位置进行修补,这不一定与定义对象的位置相同”。
→ 所以也许

sleep
方法是 not 替换所有模块?

文章还说明了一个主模块

b

  • 如果

    SomeClass
    从模块
    a
    导入并且
    SomeClass()
    在主模块
    b
    中调用→
    SomeClass
    在主模块中查找
    b

  • 如果模块

    a
    被导入并且
    a.SomeClass()
    在主模块中被调用
    b
    SomeClass
    在模块中查找
    a

    → 这就是为什么

    sleep
    在场景 A 中被全局模拟而在场景 B 中被局部模拟的原因吗?但是,在这两种情况下,
    sleep
    不只是对相同的
    time.sleep
    方法的引用吗?

根据this讨论,在不同模块中导入(例如)

time
意味着sharing
time
模块。并且在主模块中修补它的方法也为所有其他模块修补它。而在 main 中修补整个
time
模块只会改变 main 中 time
reference

→ 我很困惑。为什么这样?我们什么时候有引用,什么时候共享模块,什么时候全局模拟,什么时候局部模拟,这一切背后的逻辑是什么?

设置(不工作,场景 A):

main.py:

import time
import module

def sleep_in_main():
    time.sleep(1)  # this is mocked
    module.sleep_in_module()

模块.py:

import time

def sleep_in_module():
    time.sleep(1)  # this is also mocked

测试.py:

import main

def test(mocker):
    sleep_mock = mocker.patch("main.time.sleep")
    main.sleep_in_main()
    assert sleep_mock.call_count == 1  # fails (is called twice)

设置(工作,场景 B):

main.py:

from time import sleep
import module

def sleep_in_main():
    sleep(1)  # this is mocked
    module.sleep_in_module()

模块.py:

from time import sleep

def sleep_in_module():
    sleep(1)  # this is not mocked

测试.py:

import main

def test(mocker):
    sleep_mock = mocker.patch("main.sleep")
    main.sleep_in_main()
    assert sleep_mock.call_count == 1  # passes
python import scope mocking patch
© www.soinside.com 2019 - 2024. All rights reserved.