【问题标题】:Pytest: unit test to reproduce OSErrorPytest:单元测试重现 OSError
【发布时间】:2021-10-19 09:59:35
【问题描述】:

如何重现 OSError 以便知道我的异常有效?

def write_file():
    try: 
        with open('file.txt', "w+") as f:
            f.write("sth")
        f.close()
    except OSError as e:
        logging.error("OSError occured")

我想使用 pytest 为函数 write_file() 编写单元测试。如何模拟OSError

【问题讨论】:

  • 您的代码目前不会引发OSError,并且您在使用上下文管理器时不需要调用f.close()
  • @Alex 在文件未找到或某事的情况下,我希望异常处理和测试日志的内容。这可能吗?
  • @Alex:关键是如何引发错误。
  • @Jane:您正在打开文件进行写入,这意味着当找不到文件时它永远不会引发错误(在这种情况下会创建它)。如果当前工作目录不再存在或当前用户对当前工作目录没有写访问权限,您确实会收到 OSError 异常。
  • @MartijnPieters 我知道,但这是捕获/检测 OSError 所需要的;而且,正如 cmets 所显示的,OP 实际上想要捕获日志,所以 caplog,而不是 pytest.raises

标签: python exception mocking pytest oserror


【解决方案1】:

您必须模拟出open() 调用。您可以使用standard library unittest.mock.patch() functionpytest monkeypatch fixture 这样做;我个人更喜欢在这里使用标准库:

import pytest
import logging
from unittest import mock
from module_under_test import write_file

def test_write_file_error(caplog):
    caplog.clear()
    with mock.patch("module_under_test.open") as mock_open:
        mock_open.side_effect = OSError
        write_file()

    assert caplog.record_tuples == [("root", logging.ERROR, "OSError occured")]

mock.patch() 上下文管理器设置在 module_under_test 全局命名空间中放置了一个模拟的 open 对象,屏蔽了内置的 open() 函数。将side_effect 属性设置为异常可确保调用模拟对象将引发该异常。

模拟open() 比尝试创建内置open() 函数会引发异常的确切文件系统环境要容易得多。此外,您正在测试您自己的代码 如何正确处理OSError,而不是测试open() 是否按设计工作。

一些旁注:

  • 无需拨打f.close();您正在将打开的文件用作上下文管理器 (with ... as f:),因此无论with 块中发生什么,它都会自动关闭。
  • 正确的拼写是发生 (double r) :-)
  • 当您不打算使用e 对异常的引用时,不要使用except OSError as e:;删除 as e 部分。
  • 如果您使用logging.exception() function,则会在日志中捕获异常和完整的回溯,作为ERROR 级别的消息。
def write_file():
    try: 
        with open('file.txt', "w+") as f:
            f.write("sth")
    except OSError:
        logging.exception("Failed to write to file.txt")

【讨论】:

    【解决方案2】:

    你想做两件事:

    1. 使open() 失败并显示OSError。为了实现这一点,you could use
    @pytest.fixture(scope="function")
    def change_test_dir(request):
        os.chdir('/')
        yield
        os.chdir(request.config.invocation_dir)
    

    因为我假设你不允许写/

    1. 您想测试是否出现了正确的logging 错误。见here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      相关资源
      最近更新 更多