【问题标题】:Python: Mock ImportError with pytest.fixturePython:使用 pytest.fixture 模拟 ImportError
【发布时间】:2019-10-30 16:45:37
【问题描述】:

我正在尝试对一个对导入成功与否做出反应的辅助函数进行测试。

成功的测试有效,但失败的测试无效,你知道为什么吗?

助手: homeassistant/components/owntracks/helper.py

"""Helper for OwnTracks."""
try:
    import nacl
except ImportError:
    nacl = None

import logging

_LOGGER = logging.getLogger(__name__)


def supports_encryption() -> bool:
    """Test if we support encryption."""
    _LOGGER.info(nacl)
    return nacl is not None

我的测试: 测试/组件/owntracks/test_helper.py

"""Test the owntracks helper."""
from unittest.mock import patch
import pytest
import logging

from homeassistant.components.owntracks.helper import supports_encryption

_LOGGER = logging.getLogger(__name__)

@pytest.fixture(name="nacl_imported")
def mock_nacl_imported():
    """Mock a successful import."""
    with patch("homeassistant.components.owntracks.helper.nacl"):
        yield


@pytest.fixture(name="nacl_not_imported")
def mock_nacl_not_imported():
    """Mock non successful import."""
    with patch("homeassistant.components.owntracks.helper.nacl") as mock_import:
        mock_import.return_value = ImportError()
        yield mock_import


def test_supports_encryption(nacl_imported):
    """Test if env supports encryption."""
    _LOGGER.info(supports_encryption())
    assert supports_encryption()


def test_supports_encryption_failed(nacl_not_imported):
    """Test if env does not support encryption."""
    _LOGGER.info(supports_encryption())
    assert not supports_encryption()

也试过了:

    with patch("homeassistant.components.owntracks.helper.nacl", return_value=None):
        yield

AND

    with patch("homeassistant.components.owntracks.helper.nacl", side_effect=ImportError()):
        yield

测试日志:

 py.test tests/components/owntracks/test_helper.py
Test session starts (platform: linux, Python 3.7.4, pytest 5.2.2, pytest-sugar 0.9.2)
rootdir: /home/quentin.pollet@sglk.local/Documents/home-assistant, inifile: setup.cfg
plugins: timeout-1.3.3, cov-2.8.1, requests-mock-1.7.0, aiohttp-0.3.0, sugar-0.9.2
collecting ... 
 tests/components/owntracks/test_helper.py ✓                                       50% █████     

―――――――――――――――――――――――――――――――― test_supports_encryption_failed ――――――――――――――――――――――――――――――――

nacl_not_imported = <MagicMock name='nacl' id='139733318227280'>

    def test_supports_encryption_failed(nacl_not_imported):
        """Test if env does not support encryption."""
        _LOGGER.info(supports_encryption())
>       assert not supports_encryption()
E       assert not True
E        +  where True = supports_encryption()

tests/components/owntracks/test_helper.py:34: AssertionError
------------------------------------- Captured stderr call --------------------------------------
INFO:homeassistant.components.owntracks.helper:<MagicMock name='nacl' id='139733318227280'>
INFO:tests.components.owntracks.test_helper:True
INFO:homeassistant.components.owntracks.helper:<MagicMock name='nacl' id='139733318227280'>
--------------------------------------- Captured log call ---------------------------------------
INFO     homeassistant.components.owntracks.helper:helper.py:14 <MagicMock name='nacl' id='139733318227280'>
INFO     tests.components.owntracks.test_helper:test_helper.py:33 True
INFO     homeassistant.components.owntracks.helper:helper.py:14 <MagicMock name='nacl' id='139733318227280'>

 tests/components/owntracks/test_helper.py ⨯                                      100% ██████████

Results (0.15s):
       1 passed
       1 failed
         - tests/components/owntracks/test_helper.py:31 test_supports_encryption_failed

我是 Python 的新手,但很有动力,要友善 ;)

【问题讨论】:

    标签: python-3.x patch python-mock


    【解决方案1】:

    从您给定的详细信息可以看出,方法 supports_encryption() 将检查 nacl 的导入状态。如果没有安装,那么它会将 nacl 值更改为 False。此外,在此之后,您正在使用 True/False 验证 nacl 的值(nacl 不是 None 将返回 True,如果它不是 None)。

    supports_encryption() 的返回值将始终为 True。

    在测试方法 test_supports_encryption_failed() 中,您使用了 assert not supports_encryption(),这就是它失败的原因。

    要模拟导入值,请使用以下内容:-

    $ pytest -vsx test_11.py
    platform linux2 -- Python 2.7.15+, pytest-4.6.6, py-1.8.0, pluggy-0.13.0 -- /usr/bin/python
    cachedir: .pytest_cache
    metadata: {'Python': '2.7.15+', 'Platform': 'Linux-4.15.0-60-generic-x86_64-with-Ubuntu-18.04-bionic', 'Packages': {'py': '1.8.0', 'pytest': '4.6.6', 'pluggy': '0.13.0'}, 'Plugins': {u'html': u'1.22.0', u'metadata': u'1.8.0'}}
    rootdir: /home/nikhilesh
    plugins: html-1.22.0, metadata-1.8.0
    collected 2 items                                                                                                                                                      
    
    test_11.py::test_success ('Value is ', <module 'os' from '/usr/lib/python2.7/os.pyc'>)
    PASSED
    test_11.py::test_fail ('Value is ', None)
    PASSED
    
    ======================================================================= 2 passed in 0.07 seconds =======================================================================
    $ cat test_11.py 
    import utility
    import mock
    
    
    
    def test_success():
        print("Value is ", utility.os)
    
    
    
    @mock.patch("utility.os", return_value = None)
    def test_fail(mock_os):
        print("Value is ", utility.os.return_value)
    

    【讨论】:

    • 嗨!感谢您的回答 :) 但是如果我可以更正 nacl 的值将变为 None,而不是 False ?我不明白为什么使用not supports_encryption() 会使我的测试失败。我应该使用supports_encryption() == False 吗?我认为是一样的。另外,我的目标是测试supports_encryption(),而不是nacl 的值。我还将使用@mock.patch 而不是@pytest.fixture 进行测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多