如何使用Python的“unittest”来测试编写文件的函数

15 浏览
0 Comments

如何使用Python的“unittest”来测试编写文件的函数

我有一个Python函数,用于将输出文件写入磁盘。

我想使用Python的unittest模块为它编写一个单元测试。

我应该如何断言文件的相等性?我希望在文件内容与期望内容不同时得到错误+差异列表。就像Unix的diff命令的输出一样。

有没有官方或推荐的方法可以这样做?

admin 更改状态以发布 2023年5月23日
0
0 Comments

最简单的方法是先编写输出文件,读取其内容,读取黄金(期望)文件的内容,然后比较它们是否相同。如果相同,则删除输出文件,否则引发断言。

这样,在测试完成后,每个失败的测试将通过一个输出文件表示,您可以使用第三方工具与黄金文件进行比较(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)

0
0 Comments

我更喜欢输出函数明确地接受文件句柄(或文件类对象),而不是接受文件名并自行打开文件。这样,我可以在我的单元测试中将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)。

0