<p>您必须模拟<code>open()</code>调用。您可以使用<a href="https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch" rel="nofollow noreferrer">standard library ^{<cd2>} function</a>,或者使用<a href="https://docs.pytest.org/en/6.2.x/monkeypatch.html" rel="nofollow noreferrer">^{<cd3>} ^{<cd4>} fixture</a>;我个人更喜欢在这里使用标准库:</p>
<pre><code>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")]
</code></pre>
<p><code>mock.patch()</code>上下文管理器安装程序在<code>module_under_test</code>全局命名空间中放置模拟的<code>open</code>对象,屏蔽内置的<code>open()</code>函数。将<code>side_effect</code>属性设置为异常可确保调用模拟对象将引发该异常</p>
<p>模拟<code>open()</code>远比尝试创建确切的文件系统环境容易,在这种环境下,内置的<code>open()</code>函数将引发异常。此外,您正在测试自己的代码</em>如何正确处理<code>OSError</code>,而不是<code>open()</code>是否按设计工作</p>
<p>一些旁注:</p>
<ul>
<li>不需要调用<code>f.close()</code>;您将打开的文件用作上下文管理器(<code>with ... as f:</code>),因此无论在<code>with</code>块中发生什么,它都会自动关闭</李>
<li>正确的拼写是<em>发生</em>(double<em>r</em>):-)</li>
<li>当您不打算使用异常的<code>e</code>引用时,不要使用<code>except OSError as e:</code>;删除<code>as e</code>部分</李>
<li>如果使用<a href="https://docs.python.org/3/library/logging.html#logging.exception" rel="nofollow noreferrer">^{<cd20>} function</a>,那么异常和完整回溯将作为<code>ERROR</code>级消息捕获到日志中</李>
</ul>
<pre><code>def write_file():
try:
with open('file.txt', "w+") as f:
f.write("sth")
except OSError:
logging.exception("Failed to write to file.txt")
</code></pre>