首页 > 解决方案 > 使用 PyTest 测试被修饰的异常处理程序被调用

问题描述

我使用装饰器来处理 Python 中的异常。这是装饰器功能:

def docker_exception_handler(func):
    def wrapper(*args, **kwargs):
        logger = logging.getLogger('docker_exception')
        try:
           func(*args, **kwargs)
        except SubProcessException:
           logger.critical(
               f'Failed to pull {args[1]} in function {func.__name__}\n')

    return wrapper

现在我想在调用 SubProcessException 引发此函数时使用 Pytest。就像是:

@docker_exception_handler
def trigger_docker_error(class_name, docker_image):
    raise PullDockerImageError

def test_docker_error():
    with patch.object(customized_exceptions,
                  'docker_exception_handler') as mock:
         trigger_docker_error("test", "test_docker_image")
    mock.assert_called_once()

但是模拟没有接到电话,失败的消息 AssertionError: Expected 'docker_exception_handler' to have been called once. Called 0 times 我不知道为什么。

标签: pythonpytestpytest-mock

解决方案


装饰器在导入时应用,因此在运行时模拟它们并断言某些东西没有多大意义。

在您的情况下,您可以模拟记录器并检查它是否使用正确的参数调用。在这里,我使用mocker来自pytest-mock

import functools
import logging

def exception_handler(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        logger = logging.getLogger('docker_exception')
        try:
           func(*args, **kwargs)
        except Exception:
           logger.critical(
               f'Failed to pull {args[1]} in function {func.__name__}\n')
    return wrapper

@exception_handler
def trigger_error(class_name, docker_image):
    raise TypeError()

def test_error(mocker):
    logger = logging.getLogger('docker_exception')
    mock = mocker.patch.object(logger, 'critical')

    trigger_error("test", "test_docker_image")

    mock.assert_called_once()
    mock.assert_called_with(f'Failed to pull test_docker_image in function trigger_error\n')

if __name__ == "__main__":
    import pytest
    pytest.main([__file__])


推荐阅读