编写一个pytest函数来检查Python中文件输出的内容?

38

我曾经询问过这个问题,关于如何编写一个 pytest 来检查 stdout 中的输出并得到了解决方案。现在我需要编写一个测试用例,来检查内容是否被写入文件,并且内容是否符合预期。

def writetoafile():
   file = open("output.txt",w)
   file.write("hello\n")
   file.write("world\n")
   file.close()

现在有一个pytest函数,用于检查它是否编写正确:

def test_writeToFile():
    file = open("ouput.txt",'r')
    expected = "hello\nworld\n"
    assert expected==file.read()
虽然这似乎可以工作,但我认为这并不理想,特别是硬编码。通常如何编写这些测试函数将内容写入文件?
结果:

虽然这似乎可以工作,但我认为这并不理想,特别是硬编码。通常如何编写这些测试函数将内容写入文件?


为什么这不是理想的呢?你写道你想要检查内容是否按预期编写,因此查看文件并检查似乎是最佳选择。您可以始终创建一个带有一系列随机字符的变量,并检查是否已成功编写它;您可以检查“expected in file.read()”,以查看数据是否已附加(但您在此处使用了标志“w”,因此这是一个错误的测试);等等。如果不是这个,您想要测试什么?也许在大多数测试中,知道您想要什么才是真正的问题。 - Pierre-Francoys Brousseau
2个回答

45

有一个tmpdir fixture可以为每个测试创建一个临时目录。因此,测试看起来像这样:

def writetoafile(fname):
    with open(fname, 'w') as fp:
        fp.write('Hello\n')

def test_writetofile(tmpdir):
    file = tmpdir.join('output.txt')
    writetoafile(file.strpath)  # or use str(file)
    assert file.read() == 'Hello\n'

在这里,您正在重构代码,使其不再是硬编码的,这也是通过测试代码如何让您更好地设计它的一个典型例子。


tmpdir是做什么的?它会在内存中虚拟创建一个文件吗? - brain storm
2
它创建了一个真实的目录,您可以在之后检查它,在UNIX上,您通常会在/tmp/pytest-xxxx中找到它们,并带有指向最新运行的符号链接。您可以通过调用py.test --fixtures来了解有关固定装置的信息,对于tmpdir案例,请参阅http://pytest.org/latest/tmpdir.html以获取更多详细信息。 - flub
1
pytest.org/latest/tmpdir.html 不再存在。 - Valentyn
文档链接是404。您应该始终直接将文档粘贴到您的答案中。 - Leogout
从文档中提取:您可以使用tmpdir装置,该装置将提供一个临时目录,该目录唯一,创建在基本临时目录中。tmpdir是一个py.path.local对象,它提供了os.path方法和更多功能。以下是示例测试用法: def test_create_file(tmpdir): p = tmpdir.mkdir("sub").join("hello.txt") - Leogout
1
已更新文档链接,请注意现在您可能会使用tmp_path而不是tmpdir。我认为答案已经包含了如何使用API的示例,所以不太确定您复制文档的意思。 - flub

19

假设你有这样一段“惊人”的软件代码,保存在名为main.py的文件中:

"""
main.py
"""

def write_to_file(text):
    with open("output.txt", "w") as h:
        h.write(text)

if __name__ == "__main__":
    write_to_file("Every great dream begins with a dreamer.")

为了测试write_to_file方法,你可以在同一文件夹中创建一个名为test_main.py的文件,然后写入以下内容:

"""
test_main.py
"""
from unittest.mock import patch, mock_open

import main


def test_do_stuff_with_file():
    open_mock = mock_open()
    with patch("main.open", open_mock, create=True):
        main.write_to_file("test-data")

    open_mock.assert_called_with("output.txt", "w")
    open_mock.return_value.write.assert_called_once_with("test-data")

我总是尽量避免将文件写入磁盘,即使只是专门用于我的测试的临时文件夹:不实际接触磁盘可以使你的测试速度更快,特别是如果你在代码中频繁地与文件交互。


1
谢谢你的回答,提到模拟测试非常有帮助。这是一篇关于测试(包括像模拟测试这样的DoubleTests)的精彩文章:https://martinfowler.com/articles/practical-test-pyramid.html - aderchox
2
这应该是正确的答案。在测试中,始终避免对磁盘进行读写操作。虽然可能会更加“冗长”,但测试将运行得更快,并且比flub提供的答案更能够隔离正在进行测试的内容。 - Chris Collett
1
这非常有帮助!我需要做的唯一更改是在调用patch(...)时将“main.open”替换为“builtins.open”。 - Scott Brenstuhl
3
我不会说“总是”避免做任何事情。有时候,您想要断言您的代码实际上正在处理文件系统,就像您认为的那样。 - trpt4him
请问您能否提供使用pytest库的相同代码吗?谢谢。 - blunova
1
@blunova:以上代码也可以与pytest一起使用,只需在常规的pip install pytest之后运行pytest,测试文件将自动被发现并运行。 - Enrico Marchesin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接