Python:如何在测试套件中创建临时文件?

发布于 2024-10-02 10:34:39 字数 165 浏览 4 评论 0原文

(我正在使用 Python 2.6 和 nose。)

我正在为我的 Python 应用程序编写测试。我想要一个测试来打开一个新文件,关闭它,然后删除它。当然,我更喜欢这发生在临时目录中,因为我不想破坏用户的文件系统。而且,它需要是跨操作系统的。

我该怎么做?

(I'm using Python 2.6 and nose.)

I'm writing tests for my Python app. I want one test to open a new file, close it, and then delete it. Naturally, I prefer that this will happen inside a temporary directory, because I don't want to trash the user's filesystem. And, it needs to be cross-OS.

How do I do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

巨坚强 2024-10-09 10:34:39

FWIW 使用 py.test 您可以编写:

def test_function(tmpdir):
    # tmpdir is a unique-per-test-function invocation temporary directory

使用“tmpdir”函数参数的每个测试函数将获得一个干净的空目录,创建为“/tmp/pytest-NUM”的子目录(linux,win32 有不同的路径),其中 NUM每次测试运行都会增加。保留最后三个目录以便于检查,旧的目录将被自动删除。您还可以使用 py.test --basetemp=mytmpdir 设置基本临时目录。

tmpdir 对象是一个 py.path.local 对象,也可以像这样使用:

sub = tmpdir.mkdir("sub")
sub.join("testfile.txt").write("content")

但也可以将其转换为“字符串”路径:

tmpdir = str(tmpdir)

FWIW using py.test you can write:

def test_function(tmpdir):
    # tmpdir is a unique-per-test-function invocation temporary directory

Each test function using the "tmpdir" function argument will get a clean empty directory, created as a sub directory of "/tmp/pytest-NUM" (linux, win32 has different path) where NUM is increased for each test run. The last three directories are kept to ease inspection and older ones are automatically deleted. You can also set the base temp directory with py.test --basetemp=mytmpdir.

The tmpdir object is a py.path.local object which can also use like this:

sub = tmpdir.mkdir("sub")
sub.join("testfile.txt").write("content")

But it's also fine to just convert it to a "string" path:

tmpdir = str(tmpdir)
淡淡的优雅 2024-10-09 10:34:39

请参阅标准库中的 tempfile 模块

以下是 使用 TemporaryFileTemporaryDirectory 的示例 > 作为上下文管理器:

with tempfile.TemporaryFile() as fp:
    fp.write(b'Hello world!')
    fp.seek(0)
    fp.read()
with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary directory', tmpdirname)

See the tempfile module in the standard library

Here are the examples of using TemporaryFile and TemporaryDirectory as context managers:

with tempfile.TemporaryFile() as fp:
    fp.write(b'Hello world!')
    fp.seek(0)
    fp.read()
with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary directory', tmpdirname)
烟酒忠诚 2024-10-09 10:34:39

我建议不要直接使用 tempfile ,而是使用上下文管理器包装器 - 上下文管理器需要小心在所有情况下(成功/失败/异常)删除目录,基本上没有样板。

以下是它的使用方法:

from tempfile import TempDir    # "tempfile" is a module in the standard library
...

# in some test:
with TempDir() as d:
    temp_file_name = os.path.join(d.name, 'your_temp_file.name')
    # create file...
    # ...
    # asserts...

到目前为止,当我也需要在其他地方使用它时,我一直在使用自制版本(实现相当短 - 不到 20 行),所以我环顾四周是否有准备安装的包,确实有: tempfile


注意:上面的代码片段有点过时的。

Instead of using tempfile directly I suggest using a context manager wrapper for it - the context manager takes care of removing the directory in all cases (success/failure/exception) with basically no boilerplate.

Here is how it can be used:

from tempfile import TempDir    # "tempfile" is a module in the standard library
...

# in some test:
with TempDir() as d:
    temp_file_name = os.path.join(d.name, 'your_temp_file.name')
    # create file...
    # ...
    # asserts...

I have been using a home grown version (the implementation is rather short - under 20 lines) up to the point, when I needed to use it somewhere else as well, so I looked around if there is a package ready to install, and indeed there is: tempfile


Note: the code snippet above is a little out-dated.

水中月 2024-10-09 10:34:39

要为测试创建包含自定义内容的临时文件,您可以使用此类:

import os, tempfile

class TestFileContent:                                                                                                  
    def __init__(self, content):                                                                                        

        self.file = tempfile.NamedTemporaryFile(mode='w', delete=False)                                                 

        with self.file as f:                                                                                            
            f.write(content)                                                                                            

    @property                                                                                                           
    def filename(self):                                                                                                 
        return self.file.name                                                                                           

    def __enter__(self):                                                                                                
        return self                                                                                                     

    def __exit__(self, type, value, traceback):                                                                         
        os.unlink(self.filename)                                                                                        

此类将创建一个临时文件,在其中写入您的内容,然后关闭该文件。
您可以在 with 语句中使用它,以确保文件在使用后被删除,如下所示:

    with TestFileContent(
'''Hello, world
'''
    ) as test_file:

        # Here, a temporary file has been created in the file named test_file.filename with the specified content
        # This file will be deleted once you leave the with block

To create a temporary file with custom content for your tests you can use this class:

import os, tempfile

class TestFileContent:                                                                                                  
    def __init__(self, content):                                                                                        

        self.file = tempfile.NamedTemporaryFile(mode='w', delete=False)                                                 

        with self.file as f:                                                                                            
            f.write(content)                                                                                            

    @property                                                                                                           
    def filename(self):                                                                                                 
        return self.file.name                                                                                           

    def __enter__(self):                                                                                                
        return self                                                                                                     

    def __exit__(self, type, value, traceback):                                                                         
        os.unlink(self.filename)                                                                                        

This class will create a temporary file, write your content inside it and then close the file.
You use it inside a with statement to ensure that the file is deleted after usage like this:

    with TestFileContent(
'''Hello, world
'''
    ) as test_file:

        # Here, a temporary file has been created in the file named test_file.filename with the specified content
        # This file will be deleted once you leave the with block
咽泪装欢 2024-10-09 10:34:39

Python 3.2+

tempfileTemporaryDirectory( ) 与上下文管理器携手with是正确的出路。但是请注意,这实际上会创建临时目录(在某些操作系统目录中用于临时文件(在 Linux 上可能是 /tmp)) - 那里的文件实际上会使用存储设备/磁盘 - 它可能不会对您来说是一个问题,但是当付费服务等使用量很大时需要考虑(有关替代方案,请参阅此答案帖子的末尾)。

我还建议使用 osos.path.join() 将内容放在那里并一般使用它以避免有关 \ 的跨平台错误或 / 路径。

注意:当不使用上下文管理器时,您将获得TemporaryDirectory类的对象并使用检索名称.name
在上下文管理器中使用时,您将获得分配给 as 变量的名称字符串

TL;DR:代码

import tempfile
import os
with tempfile.TemporaryDirectory() as tempdir:
  # you can e.g. create a file here:
  tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.txt')
  with open(tmpfilepath, 'w') as tmpfile:
    tmpfile.write("something")

更改临时目录位置

在此处 您必须更深入地挖掘,因为 文档 是一种这里模糊:它根本不记录其参数,但是,它会将您发送到 mkdtemp() 应该使用相同的规则,并将您发送到 mkstemp() 您最终可以在其中确保自己使用 dir 参数来覆盖默认目录位置。

您想完全伪造文件系统上的 I/O(输入/输出)操作吗?

您可以尝试按照此答案中的建议使用 pyfakefshttps://stackoverflow.com/a/46817032/1835470

哪个更好?伪造文件系统或物理临时目录?

取决于使用情况 - 通常组合可以是一个很好的折衷方案 - 使用真实的目录和文件单独测试每个文件系统操作,以便您知道它确实有效,但对于您自定义的大量使用的东西,请使用伪造/模拟文件系统操作:)另外例如,对于测试来自操作系统内部的权限 - 使用物理方式可能会更好。

您必须始终事先评估您可以获得多少性能和耐用性,以及进行额外测试是否有意义。

Python 3.2+

tempfile library TemporaryDirectory() hand in hand with context manager with is the way to go. However DO note, that this PHYSICALLY creates the temporary directory (in some OS dir for temp. files (on linux probably /tmp)) - files there would actually use the storage device/disk - it may not be a problem for you, but it is something to consider when that usage would be heavy on e.g. a paid service (for alternatives see the the end of this answer post).

I also suggest using os library os.path.join() to put stuff there and to use it in general to avoid cross-platform bugs regarding \ or / paths.

Note: When used without context manager with you get object of TemporaryDirectory class and retrieve the name with .name
, when used in context manager you get the name string assigned to your as variable.

TL;DR : The code

import tempfile
import os
with tempfile.TemporaryDirectory() as tempdir:
  # you can e.g. create a file here:
  tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.txt')
  with open(tmpfilepath, 'w') as tmpfile:
    tmpfile.write("something")

Change the temporary directory location

Here you must a dig a bit deeper, since documentation is kind of fuzzy here: it does not document its arguments at all, but, it sends you to mkdtemp() which should use same rules and there it sends you to mkstemp() where you can finally sort of ensure yourself, that the dir argument is used to override the default directory placement.

Do you want to completely fake the I/O (input/output) operations on your filesystem?

You can try using pyfakefs as suggested in this answer: https://stackoverflow.com/a/46817032/1835470

Which one is better? faking filesystem or a physical temporary dir?

Depends on the usage - usually a combination can be a good compromise - test each filesystem operation on its own with real directories and files so you know it really works, but for your custom heavy-usage stuff use faking/mocking filesystem operations :) Also for testing permissions coming from within the OS for example - it would probably be better to use the physical way.

You must always evaluate beforehand how much performance and durability is available to you and if it makes sense to make an extra testing or not.

香橙ぽ 2024-10-09 10:34:39

For people who come across this in the future, but also refuse to use pytest for some reason:

I wrote tempcase, a small library which provides a unittest.TestCase subclass with convenience methods for handling temporary directories. No directories are created until you request the path to them, and they are namespaced to the project, TestCase class, timestamp, and test method. They are automatically cleaned up afterwards. You can disable cleanup to inspect the output by setting a property.

There is also a decorator which can be applied to individual test cases, if you're porting code gradually.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文