【问题标题】:Automatically delete MEDIA_ROOT between tests在测试之间自动删除 MEDIA_ROOT
【发布时间】:2014-09-11 16:32:58
【问题描述】:

我想知道是否有可能,最好不要太难,使用 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'))

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

【问题讨论】:

    标签: python django unit-testing


    【解决方案1】:

    The answer by 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
    

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

    【讨论】:

      【解决方案2】:

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

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

      我认为this page 上的文章是最佳实践。如果您不关心推理,我将复制/粘贴下面的代码 sn-p (后面有更多注释):

      ----

      首先,让我们编写一个基本的、非常基本的模型

      from django.db import models
      
      class Picture(models.Model):
          picture = models.ImageField()
      

      然后,让我们编写一个非常非常基本的测试。

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

      ----

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

      还有可能对您有用的是,如何将设置覆盖轻松应用于测试类,而不仅仅是一个测试功能。详情请见this page

      在这篇文章之后的 cmets 中还要注意,有些人展示了一种更简单的方法来获取临时文件名,而无需担心使用 NamedTemporaryFile 的媒体设置(仅适用于不使用媒体设置!)

      【讨论】:

        【解决方案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)
        

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

        【讨论】:

        • 我同意使用 Setup 和 TeadDown。但是,盲目删除文件系统上的文件夹并不是一个好主意!您可以在 init 文件中覆盖 TestCase 类的部分内容,以创建一个真正的全局版本的 TestCase 来满足您的需求。但是,我希望您测试不需要/不想要此修改的代码的其他部分。这使得 Setup/Teardown 仅针对需要它的类成为最佳实践。但请参阅下面的答案以获得更安全的解决方案。
        【解决方案4】:

        类似的东西?

        TESTING_MODE = True
        ...
        MEDIA_ROOT = os.path.join(DJANGO_ROOT, 'media_test' if TESTING_MODE else 'media')
        

        【讨论】:

        • 我已经把那部分整理好了,我目前正在使用单独的媒体目录进行测试。我只是想让它成为一个临时文件,在文件浏览器中通常是半透明的。我最想知道的是如何在每次测试之间自动删除 MEDIA_ROOT。类似于在每次测试之间重置测试数据库的方式。
        猜你喜欢
        • 2014-03-17
        • 2019-03-06
        • 2010-12-15
        • 1970-01-01
        • 2018-08-06
        • 1970-01-01
        • 2017-03-05
        • 1970-01-01
        • 2021-12-01
        相关资源
        最近更新 更多