Python 单元测试文件写入

3 投票
3 回答
6512 浏览
提问于 2025-04-15 17:55

我正在为Python中的ConfigParser写一个封装器,目的是提供一个简单的接口来存储和获取应用程序的设置。

这个封装器有两个方法,分别是readwrite,还有一组属性用来处理不同的应用设置。

其中,write方法其实就是对ConfigParserwrite方法的封装,额外的功能是创建ConfigParser所需的文件对象。它的代码大致是这样的:

def write(self):
    f = open(self.path, "w")
    try:
        self.config_parser.write(f)
    finally:
        f.close()

我想写一个单元测试,来验证这个方法在无法写入文件时会抛出IOError,同时在其他情况下,确认配置解析器的写入方法被调用了。

第二个测试相对简单,可以用一个模拟对象来处理。但是open这个调用就有点麻烦了。最终我需要创建一个文件对象来传递给配置解析器。实际上在运行这段代码时会创建一个文件,这让它在单元测试中不太实用。有没有什么策略可以模拟文件的创建?这段代码能以某种方式进行测试吗?还是说它太简单了,不值得测试?

3 个回答

2

记住,你不需要测试 open() 或 ConfigParser 这些功能,因为它们不是你自己写的代码。你只需要确保你正确地使用了它们。你可以用自己的 open() 来替换这个模块,就像替换实例属性一样,这样你就可以返回一个模拟的结果,帮助你进行测试。

不过,单元测试并不是我唯一的工具,这个函数足够简单,可以直接分析和“证明”它是有效的。

虽然这种证明方式可能没有数学家们想要的那么严格,但对我来说已经足够了。

5

其实,只有打开文件的那部分代码可能会出错。关于写入(write())的文档没有提到会有异常。可能只有在文件指针不对的时候会出现一个ValueError(这通常是因为打开文件失败,但在这里不可能出现这种情况)。

让打开文件时出现IOError其实很简单。你可以在其他地方创建这个文件,然后在那里打开它进行写入。或者你可以更改文件的权限,让你没有访问权限。

不过你可能想在这里使用with语句,这样它会自动处理文件的关闭。

在Python 2.5中,你需要第一行代码。在后来的版本中就不需要了。

from __future__ import with_statement # python 2.5 only

def write(self):
    with open(self.path, 'w') as f:
        self.config_parser.write(f)

如果open成功,写入方法一定会被调用;如果open抛出一个IOError,那么写入方法就不会被调用。我不知道你为什么需要测试写入是否被调用。代码已经说明它会被调用。别过于测试了。;)

8

首先,其实你并不需要对 open() 进行单元测试,因为我们可以合理地认为标准库是正确的。

接下来,你也不想通过操作文件系统来让 open() 产生你想要的错误,因为那样你就不是在做单元测试,而是在做功能测试或集成测试,因为你涉及到了文件系统。

所以,你可以考虑在全局范围内用一个替代品替换 open(),这个替代品只会抛出一个 IOError。不过,执行完后可能需要确保把东西恢复回来。

但最终,这个测试有什么价值呢?在那个代码片段中,几乎没有你自己系统的东西。即使替换了 open(),其实也只是测试“Python中的 tryfinally 语句是否有效?”

我的建议是?在文档字符串中加一句记录你的期望。“如果文件无法写入,则抛出一个 IOError。”然后就可以继续了。如果这个方法后面变得复杂(并且值得测试),你可以再添加单元测试。

撰写回答