Pytest/Mock 保留额外的对象引用,以防捕获异常

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

我使用 pytest 和模拟遇到了一个奇怪的问题:我试图通过使用

__del__
删除对象来创建对
del ...
的调用。根据文档,
del
只会减少正在“删除”的对象的引用计数器,并且只有在没有其他人仍然持有对该对象的引用时才真正删除该对象。看起来如果 Mock 抛出异常,就会以某种方式导致某人获取并保留对该对象的额外引用。

我整理了一个快速演示测试来展示问题:

test_del_passes
(完成得很好)和
test_del_fails
(最后一个断言失败,即
del del_test
不会导致调用
del_test.__del__())之间的唯一区别
)是,在第一个中,
test_fn
返回一个值,而在第二个中,
test_fn
抛出一个
TimeoutError
。我尝试删除
test_fn
对象,或者将
TimeoutError
分配给变量并删除它,但我根本找不到让第二个测试通过的方法。因此,在测试的某个地方,有人保留了对
del_test
的额外引用,但我不知道谁、为什么或如何摆脱它。

import unittest.mock as mock

class DelTest:
    def __init__(self, flags, test_fn):
        self.flags = flags
        self.test_fn = test_fn

    def __del__(self):
        self.flags[0] = 1

    def run(self):
        try:
            self.test_fn()
        except TimeoutError:
            pass


def test_del_passes():
    flags = [0]
    test_fn = mock.Mock(side_effect=[True])
    del_test = DelTest(flags, test_fn)
    del_test.run()
    assert flags[0] == 0
    del del_test
    assert flags[0] == 1


def test_del_fails():
    flags = [0]
    test_fn = mock.Mock(side_effect=[TimeoutError()])
    del_test = DelTest(flags, test_fn)
    del_test.run()
    assert flags[0] == 0
    del del_test
    assert flags[0] == 1
python mocking pytest reference-counting del
1个回答
0
投票

框架保留对对象的引用,您可以看到它调用了

gc.get_referrers(del_test)

[<frame at 0x101b15080, file 'xxx.py', line 17, code run>]
© www.soinside.com 2019 - 2024. All rights reserved.