You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何测试用例结束后线程内调用的方法Mock未生效?

问题:多线程场景下Mock方法仅在sleep时生效的原因

代码文件

one.py

class One:
    def __init__(self) -> None:
        pass
        
    def startS(self):
        self._doS()

    def _doS(self):
        print("Inside doS method")
        if not self.open():
            print("The patch didn't work")
            return False

        print("The patch worked well")
        return True

    def open(self):
        print("Inside open method")
        return False

two.py

from one import One
from threading import Thread

class Two(One):
    def __init__(self) -> None:
        super().__init__()

    def startS(self):
        self.sThread = Thread(target=super().startS)
        self.sThread.daemon = True
        self.sThread.start()

测试代码(test_two.py)

import unittest
from unittest import mock
from time import sleep
from two import Two 

@mock.patch('two.One.open',  mock.Mock(return_value=True))
class TestDummy(unittest.TestCase):
   
    def test_first(self) -> None:
        self.two = Two()
        self.two.startS()
        #sleep(1)

if __name__ == '__main__':
    unittest.main()

运行结果

无sleep时的输出

Inside doS method
.Inside open method
The patch didn't work
Ran 1 test in 0.001s
OK

有sleep时的输出

Inside doS method
The patch worked well
.
Ran 1 test in 1.002s
OK

原因解析

核心问题是守护线程的执行时序与测试上下文的生命周期不匹配:

  • @mock.patch的生效范围仅限于测试方法test_first的执行过程,一旦测试方法执行完毕,Mock会被立即撤销。
  • 调用self.two.startS()后,守护线程是异步启动的,但测试方法会立刻执行结束,此时Mock已经失效。而守护线程可能在Mock撤销后才开始调用open(),这时调用的是原类的open()方法(返回False),所以出现未生效的结果。
  • 加入sleep(1)后,测试方法会等待一段时间,让守护线程有足够时间在Mock生效期间完成open()调用,因此Mock能正常工作。

解决方法

不要依赖sleep这种不可靠的等待方式,应该主动等待线程执行完成:
修改测试方法,启动线程后调用join()等待线程结束:

def test_first(self) -> None:
    self.two = Two()
    self.two.startS()
    self.two.sThread.join()  # 等待线程执行完成

这样能确保线程在Mock生效的上下文内完成所有调用,无需sleep也能得到正确结果。

内容的提问来源于stack exchange,提问作者tatti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:58:31