Pytest:重现 OSError 的单元测试

Pytest: unit test to reproduce OSError

如何重现 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?

您想做两件事:

  1. 使 open() 失败 OSError。为此,
@pytest.fixture(scope="function")
def change_test_dir(request):
    os.chdir('/')
    yield
    os.chdir(request.config.invocation_dir)

因为我假设您不允许在 /.

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

您必须模拟 open() 调用。你可以用 standard library unittest.mock.patch() function, or with the pytest 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 块中发生什么。
  • 正确的拼写是 occurred (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")