【问题标题】:Mocking before importing a module导入模块前的模拟
【发布时间】:2011-11-09 18:07:18
【问题描述】:

我怎样才能patch and mockgetLogger在这个被测模块(MUT)中:

# Start of the module under test
import logging
log = logging.getLogger('some_logger')
# ...

我想做:

mock_logging.getLogger.return_value = Mock()

但是我不能在导入 MUT 之前创建 mock_logging,但是导入 MUT 已经调用了 getLogger...

【问题讨论】:

    标签: python logging mocking patch


    【解决方案1】:

    这可以通过首先导入和修补logging.getLogger 来完成,然后才导入您的mut

    import unittest
    from unittest import mock
    
    import logging
    with mock.patch('logging.getLogger') as mock_method:
        import mut
    mock_method.assert_called_once_with('some_logger')
    

    另外,在修补多个方法时很有用:

    import unittest
    from unittest import mock
    
    import logging
    mock_method = mock.patch('logging.getLogger').start()
    import mut
    mock_method.stop()
    mock_method.assert_called_once_with('some_logger')
    

    【讨论】:

    • 在with语句外使用mock_method对象真的可以吗?
    • 是的,我认为它是:上下文管理器的 __exit__ 仅将 mock_methodmut.logger.getLogger 解耦,使用语句不创建范围,因此,mock_method 仍在(全局)范围内并可用于断言
    【解决方案2】:

    这将需要先导入模块而不先执行它,这对你来说很不幸won't work,除非你做了一些花哨的技巧,比如修改模块的解析树,但你可能也不想这样做。

    您可以做的是在导入后修改这些导入时引用,并用模拟对象手动替换它们,或者在安装模拟对象后重新执行语句,尽管我知道这是有限的用途。

    【讨论】:

    【解决方案3】:

    您需要在模拟上下文中导入模块并在导入后从sys.modules 中删除模块,这样模拟不会在导入mut 的其他测试中持续存在:

    import sys
    from unittest import mock
    
    with mock.patch("logging.getLogger") as mock_logging:
        import mut
        del sys.modules["mut"]
    ...
    

    也可以使用 pytest:

    import sys
    import pytest
    
    def mock_get_logger(name):
        print("mock logger name", name)
    
    with pytest.MonkeyPatch().context() as ctx:
        ctx.setattr("", mock_get_logger)
        from main import app
        del sys.modules["main"]
    ...
    

    【讨论】:

      猜你喜欢
      • 2020-06-30
      • 1970-01-01
      • 1970-01-01
      • 2020-12-21
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      相关资源
      最近更新 更多