在远程模块中模拟一个对象

Mocking an object in a distant module

我在 class、ClassA 上有一些单元测试 运行。此 class 具有调用 ClassB 的方法。 ClassAClassB 在不同的模块中,class_A.pyclass_B.py。这两个模块都具有 logger 在该模块中全局可用的功能。

在测试 ClassA 的方法期间,我想禁止显示日志消息。使用 mock.patch 可以直接为 class_A.py 中的记录器执行此操作。但是我还没有找到在 class_B.py.

中修补记录器的方法

下面是一些示例代码:

unittest_file.py

import unittest
import class_A

class TestClassA(unittest.TestCase):

    def setUp(self):
        pass

    def test_method(self):
        my_class_A = class_A.ClassA()
        my_class_A.run_method()

    def tearDown(self):
        pass

class_A.py

import logging
from class_B import ClassB

logger = logging.getLogger(__name__)

class ClassA:

    run_method(self):
        my_class_B = ClassB()
        my_class_B.do_something()
        logger.info("Running method on Class A")

class_B.py

import logging

logger = logging.getLogger(__name__)

class ClassB:

    do_something(self):
        logger.info("Doing something on Class B")

要在 class_A.py 中修补记录器,我可以将 @patch('__main__.unittest_file.ClassA.logger', autospec=True) 作为装饰器添加到 test_method() 方法中。 但我无法直接访问 class_B.py 中的记录器来修补它。

我最接近的解决方案是:

@patch(eval('__main__.unittest_file.class_A.ClassB.__module__')['logger'])

但是应用于模块名称的 eval() 函数不会保留导入位置,因此它不会在正确的命名空间中修补记录器。

我知道我可以通过将 class_A.py 中的 import 语句更改为 import class_B 而不是 from class_B import ClassB 来轻松解决此问题,但我不想编辑class_A.pyclass_B.py 中的代码,所以这不是我要找的答案。

我也知道有一些方法可以通过禁用日志记录来解决这个问题,例如 this question 但我更感兴趣的是能够微调我对要测试的代码的不同部分的控制,所以这也不是我要找的答案。

我的问题是: 有没有一种方法可以让我从一个导入的对象导航到其父模块中的其他对象,同时保持在同一个命名空间中?

对我来说,只需修补 class_A.loggerclass_B.logger 即可,例如

import unittest
from unittest import mock

class TestCaseA(unittest.TestCase):

    @mock.patch('class_A.logger')
    @mock.patch('class_B.logger')
    def test_method(self, mockedA, mockedB):
        my_class_A = ClassA()
        my_class_A.run_method()

两个记录器不再输出日志消息。