在测试之间自动删除 MEDIA_ROOT

sem*_*lon 5 python django unit-testing

我想知道是否有可能,并且最好不是太难,使用 Django DiscoverRunner 在每次测试之间删除我的媒体目录,包括在最开始和最后一次。我对 Django 1.7 中引入的新属性“test_suite”和“test_runner”特别感兴趣,想知道它们是否会让这个任务变得更容易。

我还想知道如何使测试特定的 MEDIA_ROOT 成为临时文件,目前我有一个名为“media”的常规 MEDIA_ROOT 和一个名为“media_test”的测试 MEDIA_ROOT,并且我在涉及媒体的每个测试类的设置和拆卸中使用 rmtree目录。我指定使用哪个 MEDIA_ROOT 的方式在我的 test.py 设置文件中,目前我只有:

MEDIA_ROOT = normpath(join(DJANGO_ROOT, 'media_test'))
Run Code Online (Sandbox Code Playgroud)

有没有办法可以将 MEDIA_ROOT 设置为名为“media”的临时目录?

Ric*_*oke 10

这个问题有点老了,我的答案来自Django 2.0和Python 3.6.6或更高版本。虽然我认为该技术也适用于旧版本,YMMV。

\n\n

我认为这是一个比人们所认为的更重要的问题!当您编写良好的测试时,您需要快速生成测试文件或生成测试文件只是时间问题。无论哪种方式,您都有污染服务器或开发人员计算机的文件系统的危险。 两者都不可取

\n\n

我认为本页上的内容是最佳实践。如果您不关心推理,我将复制/粘贴下面的代码片段(稍后会有更多注释):

\n\n

----

\n\n

首先,让\xe2\x80\x99s 编写一个基本的、非常基本的模型

\n\n
from django.db import models\n\nclass Picture(models.Model):\n    picture = models.ImageField()\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,让\xe2\x80\x99s 编写一个非常非常基本的测试。

\n\n
from PIL import Image\nimport tempfile\nfrom django.test import TestCase\nfrom .models import Picture\nfrom django.test import override_settings\n\ndef get_temporary_image(temp_file):\n    size = (200, 200)\n    color = (255, 0, 0, 0)\n    image = Image.new("RGBA", size, color)\n    image.save(temp_file, \'jpeg\')\n    return temp_file\n\nclass PictureDummyTest(TestCase):\n\n    @override_settings(MEDIA_ROOT=tempfile.TemporaryDirectory(prefix=\'mediatest\').name)\n    def test_dummy_test(self):\n            temp_file = tempfile.NamedTemporaryFile()\n            test_image = get_temporary_image(temp_file)\n            #test_image.seek(0)\n            picture = Picture.objects.create(picture=test_image.name)\n            print "It Worked!, ", picture.picture\n            self.assertEqual(len(Picture.objects.all()), 1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

----

\n\n

我对代码片段进行了一项重要更改:TemporaryDirectory().name。原始片段使用gettempdir()。TemporaryDirectory函数每次调用时都会使用系统生成的名称创建一个新文件夹该文件夹将被操作系统删除 - 但我们不知道什么时候!这样,我们每次运行都会得到一个新文件夹,因此不会出现名称冲突。请注意,我必须添加 .name 元素才能获取生成的文件夹的名称,因为 MEDIA_ROOT 必须是字符串。最后,我添加了prefix=\'mediatest\',这样所有生成的文件夹都很容易识别,以防我想在脚本中清理它们。

\n\n

对您也可能有用的是,如何将设置覆盖轻松应用于测试类,而不仅仅是一个测试函数。详情请参阅本页。

\n\n

另请注意,在本文后面的评论中,有些人展示了一种更简单的方法来获取临时文件名,而无需担心使用NamedTemporaryFile的媒体设置 (仅对不使用媒体设置的测试有效!)

\n


Tuo*_*ila 5

Richard Cooke 的答案有效,但使临时目录留在文件系统中,至少在 Python 3.7 和 Django 2.2 上是这样。通过使用 setUpClass、tearUpClass 的组合并覆盖测试方法中的设置可以避免这种情况。例如:

import tempfile
class ExampleTestCase(TestCase):
    temporary_dir = None

    @classmethod
    def setUpClass(cls):
        cls.temporary_dir = tempfile.TemporaryDirectory()
        super(ExampleTestCase, cls).setUpClass()

    @classmethod
    def tearDownClass(cls):
        cls.temporary_dir = None
        super(ExampleTestCase, cls).tearDownClass()

    def test_example(self):
        with self.settings(MEDIA_ROOT=self.temporary_dir.name):
            # perform a test
            pass
Run Code Online (Sandbox Code Playgroud)

这样临时文件就会立即删除,您也无需担心临时目录的名称。(当然,如果您愿意,您仍然可以prefix在调用 tempfile.TemporaryDirectory 时使用该参数)


sem*_*lon 3

我发现有效的一个解决方案是简单地在setUp/tearDown中删除它,我更愿意找到某种方法让它自动应用于所有测试,而不是必须将逻辑放在涉及媒体的每个测试文件中,但我还没有还知道怎么做。

我使用的代码是:

from shutil import rmtree
from django.conf import settings
from django.test import TestCase

class MyTests(TestCase):
    def setUp(self):
        rmtree(settings.MEDIA_ROOT, ignore_errors=True)

    def tearDown(self):
        rmtree(settings.MEDIA_ROOT, ignore_errors=True)
Run Code Online (Sandbox Code Playgroud)

我在setUp和tearDown中都这样做的原因是,如果我只在setUp中使用它,我最终可能会得到一个挥之不去的media_test目录,即使它不会意外地签入到GitHub(它位于.gitignore中)它仍然在我的项目资源管理器中占用不必要的空间,我只是不想让它坐在那里占用空间。如果我只将其放在拆解中,那么如果我中途退出测试,并且它尝试运行涉及媒体的测试,而已终止的测试中的媒体仍然存在,那么我就有可能导致问题。