如何使用Python的“unittest”来测试编写文件的函数
如何使用Python的“unittest”来测试编写文件的函数
我有一个Python函数,用于将输出文件写入磁盘。
我想使用Python的unittest
模块为它编写一个单元测试。
我应该如何断言文件的相等性?我希望在文件内容与期望内容不同时得到错误+差异列表。就像Unix的diff命令的输出一样。
有没有官方或推荐的方法可以这样做?
admin 更改状态以发布 2023年5月23日
最简单的方法是先编写输出文件,读取其内容,读取黄金(期望)文件的内容,然后比较它们是否相同。如果相同,则删除输出文件,否则引发断言。
这样,在测试完成后,每个失败的测试将通过一个输出文件表示,您可以使用第三方工具与黄金文件进行比较(Beyond Compare非常适合这个过程)。
如果您真的想提供自己的比较输出,请记住 Python 标准库中有 difflib 模块。 Python 3.1 中的新 unittest 支持包括一个 assertMultiLineEqual 方法,它使用它来显示差异,类似于以下内容:
def assertMultiLineEqual(self, first, second, msg=None): """Assert that two multi-line strings are equal. If they aren't, show a nice diff. """ self.assertTrue(isinstance(first, str), 'First argument is not a string') self.assertTrue(isinstance(second, str), 'Second argument is not a string') if first != second: message = ''.join(difflib.ndiff(first.splitlines(True), second.splitlines(True))) if msg: message += " : " + msg self.fail("Multi-line strings are unequal:\n" + message)
我更喜欢输出函数明确地接受文件句柄(或文件类对象),而不是接受文件名并自行打开文件。这样,我可以在我的单元测试中将StringIO
对象传递给输出函数,然后在调用.seek(0)
之后从该StringIO
对象中.read()
内容并与我的期望输出进行比较。
例如,我们可以将代码从
##File:lamb.py import sys def write_lamb(outfile_path): with open(outfile_path, 'w') as outfile: outfile.write("Mary had a little lamb.\n") if __name__ == '__main__': write_lamb(sys.argv[1]) ##File test_lamb.py import unittest import tempfile import lamb class LambTests(unittest.TestCase): def test_lamb_output(self): outfile_path = tempfile.mkstemp()[1] try: lamb.write_lamb(outfile_path) contents = open(tempfile_path).read() finally: # NOTE: To retain the tempfile if the test fails, remove # the try-finally clauses os.remove(outfile_path) self.assertEqual(contents, "Mary had a little lamb.\n")
转换为像这样的代码
##File:lamb.py import sys def write_lamb(outfile): outfile.write("Mary had a little lamb.\n") if __name__ == '__main__': with open(sys.argv[1], 'w') as outfile: write_lamb(outfile) ##File test_lamb.py import unittest from io import StringIO import lamb class LambTests(unittest.TestCase): def test_lamb_output(self): outfile = StringIO() # NOTE: Alternatively, for Python 2.6+, you can use # tempfile.SpooledTemporaryFile, e.g., #outfile = tempfile.SpooledTemporaryFile(10 ** 9) lamb.write_lamb(outfile) outfile.seek(0) content = outfile.read() self.assertEqual(content, "Mary had a little lamb.\n")
这种方法的附加好处是,如果您决定不想写入文件而是写入其他缓冲区,它使您的输出函数更加灵活,因为它将接受所有文件类对象。
请注意,使用StringIO
假定测试输出的内容可以适合于主内存。对于非常大的输出,您可以使用临时文件方法(例如< tempfile.SpooledTemporaryFile)。