简体   繁体   English

用Python编写单元测试文件

[英]Unit testing file write in Python

I am writing a wrapper for the ConfigParser in Python to provide an easy interface for storing and retrieving application settings. 我正在用Python编写ConfigParser的包装程序,以提供用于存储和检索应用程序设置的简便接口。

The wrapper has two methods, read and write , and a set of properties for the different application settings. 包装器有两种方法, readwrite ,以及用于不同应用程序设置的一组属性。

The write method is just a wrapper for the ConfigParser 's write method with the addition of also creating the file object needed by the ConfigParser . write方法只是ConfigParserwrite方法的包装,另外还创建了ConfigParser所需的文件对象。 It looks like this: 看起来像这样:

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

I would like to write a unit test that asserts that this method raises an IOError if the file could not be written to and in the other case that the write method of the config parser was called. 我想编写一个单元测试,断言该方法在无法写入文件时引发IOError,而在另一种情况下,调用配置解析器的write方法。

The second test is quite easy to handle with a mock object. 使用模拟对象进行第二项测试非常容易。 But the open call makes things a little tricky. 但是open电话使事情变得有些棘手。 Eventually I have to create a file object to pass to the config parser. 最终,我必须创建一个文件对象以传递给配置解析器。 The fact that a file will actually be created when running this code doesn't make it very useful for a unit test. 运行此代码时实际上将创建文件的事实并不能使其对单元测试非常有用。 Is there some strategy for mocking file creation? 有一些模拟文件创建的策略吗? Can this piece of code be tested in some way? 这段代码可以通过某种方式进行测试吗? Or is it just too simple to be tested? 还是测试太简单了?

First, you don't actually need to unit test open() , since it's pretty reasonable to assume that the standard library is correct. 首先,您实际上不需要对open()进行单元测试,因为假设标准库是正确的是相当合理的。

Next, you don't want to do file system manipulations to get open() to generate the error you want, because then you're not unit testing, you're doing a functional/integration test by including the file system. 接下来,您不想执行文件系统操作来获取open()来生成所需的错误,因为这样就无需进行单元测试,而是通过包含文件系统来进行功能/集成测试。

So you could perhaps replace open() in the global namespace with a surrogate that just raises an IOError . 因此,您可以使用仅引发IOError的代理替换全局名称空间中的open() Though, probably need to make sure you put things back if execution continues. 但是,如果继续执行,可能需要确保您放回原处。

But in the end, what value does the test have? 但是最后,测试有什么价值? There's so little in that code snippet that's your own system. 您自己的系统中的代码片段很少。 Even replacing open() really just ends up being a test that says "does the try and finally statement in Python work?" 即使替换open()实际上实际上最终只是一个测试,内容为“ Python中的tryfinally语句是否起作用?”

My suggestion? 我的建议? Just add a statement to the docstring that records your expectation. 只需在文档字符串中添加一条记录您的期望的语句即可。 "Raises an IOError if the file can't be written." “如果无法写入文件,则引发IOError。” Then move on. 然后继续前进。 You can add a unit test later if this method gains some complexity (and merit for testing). 如果此方法增加了一些复杂性(以及测试的优点),则可以稍后添加单元测试。

Actually, only open could throw an exception in your code. 实际上,只有open可能在您的代码中引发异常。 The docs for write() doesn't say anything about exceptions. write()的文档未提及任何有关异常的内容。 Possibly only a ValueError or something for a bad file pointer (as a result of open failing, which can't be the case here). 可能仅是ValueError或用于错误文件指针的内容(由于打开失败而导致的情况,此处不是这种情况)。

Making an IOError for open is easy. 使IOError打开很容易。 Just create the file elsewhere and open it for writing there. 只需在其他位置创建文件并打开以在其中写入即可。 Or you could change the permissions for it so you don't have access. 或者,您可以更改其权限,因此您无权访问。

You'd might wanna use the with statement here though, and it'll handle the closing itself. 不过,您可能想在此处使用with语句,它会自行处理关闭操作。

In python 2.5 you need the first line. 在python 2.5中,您需要第一行。 In later versions you don't need it. 在更高版本中,您不需要它。

from __future__ import with_statement # python 2.5 only

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

The write method is guaranteed to be called if open succeeds, and won't be called if open raises an IOError . 如果open成功,则保证将调用write方法,如果open引发IOError ,则不会调用write方法。 I don't know why you'd need a test to see if write was called. 我不知道为什么您需要测试以查看是否调用了write。 The code says that it does. 该代码表明确实如此。 Don't overdo your testing. 不要过度测试。 ;) ;)

Remember you don't have to test that open() or ConfigParser work—they're not part of your code—you just have to test that you use them correctly. 请记住,您不必测试open()或ConfigParser的工作-它们不是代码的一部分-您只需要测试是否正确使用它们即可。 You can monkeypatch the module with your own open(), just as for the instance attribute, and can return a mock from it that helps you test. 您可以像实例属性一样,使用自己的open()对该模块进行猴子修补,并可以从中返回模拟内容来帮助您进行测试。

However, unit tests are not my only tool, and this is one function that's simple enough to analyze and "prove" that it works. 然而,单元测试是不是我唯一的工具,这是一个功能,这是很简单的分析和“证明”†,它的作品。

Less rigorously than mathematicians would like, I'm sure, but good enough for me. 我确定,严格程度不如数学家所希望,但对我来说足够好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM