在django中单元测试FileField的干净方法是什么?

时间:2010-11-26 09:16:22

标签: python django filefield django-unittest

我有一个带有FileField的模型。我想对它进行单元测试。 django测试框架有很好的方法来管理数据库和电子邮件。 FileFields有类似的东西吗?

如何确保单元测试不会污染真实的应用程序?

提前致谢

PS:我的问题几乎与Django test FileField using test fixtures重复,但它没有接受答案。只想重新询问这个主题是否有新内容。

5 个答案:

答案 0 :(得分:79)

Django提供了一种很好的方法 - 使用SimpleUploadedFile。

from django.core.files.uploadedfile import SimpleUploadedFile

my_model.file_field = SimpleUploadedFile('best_file_eva.txt', 'these are the file contents!')

这是django的魔法特征之一 - 不要在文档中显示:)。但是,它被称为here

答案 1 :(得分:36)

有几种方法可以解决这个问题,但它们都很丑陋,因为单元测试应该是隔离的,但文件都是关于持久的变化。

我的单元测试不会在具有生产数据的系统上运行,因此在每次运行后使用git reset --hard之类的内容轻松重置上载目录。这种方法在某些方面是最好的,因为它不涉及代码更改,并且只要您从良好的测试数据开始就可以保证工作。

如果在测试模型的保存方法后实际上不需要对该文件执行任何操作,我建议使用python的优秀Mock library来完全伪造File实例(例如{ {1}})这样您就可以完全避免对文件处理逻辑的更改。 Mock库有两种方法可以在测试方法中globally patch Django的File class,这很容易实现。

如果您需要一个真实的文件(即作为测试的一部分,使用外部脚本进行处理等),您可以使用类似于Mirko的示例,并在确定它之后创建File object将被存储在适当的地方 - 这有三种方法:

  • 让您的测试mock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents"指向临时目录(请参阅Python tempfile模块的settings.MEDIA_ROOT函数)。只要你有一个单独的mkdtemp,你可以使用它作为源代码的媒体文件。
  • 使用自定义storage manager
  • 在每个File实例上手动设置文件路径,或者使用自定义upload_to功能指向您的测试设置/拆卸过程清除的位置,例如STATIC_ROOT下的测试子目录。

编辑:模拟对象库是python版本3.3中的新功能。对于较旧的python版本,请检查Michael Foord's version

答案 2 :(得分:12)

我通常使用doctest

测试模型中的文件字段
>>> from django.core.files import File
>>> s = SimpleModel()
>>> s.audio_file = File(open("media/testfiles/testaudio.wav"))
>>> s.save()
>>> ...
>>> s.delete()

如果我需要,我还测试文件上传与测试客户端。

对于灯具,我只需在修改灯具中的路径后,将我需要的文件复制到测试文件夹中。

e.g。

在包含指向名为“audio”的目录的文件脚本的模型中,将“audio”:“audio / audio.wav”替换为“audio”:“audio / test / audio.wav”。
现在你要做的就是将测试文件夹和必要的文件复制到test setUp的“audio”中,然后在tearDown中删除它。

不是我认为最干净的方式,但这就是我的所作所为。

答案 3 :(得分:0)

如果您只想创建一个需要FileField的对象不想使用此字段,那么您只需传递任何(现有的或不存在的)相对路径像这样:

self.example_object = models.ExampleModel({'file': "foo.bar"})
self.example_object.save()

然后就可以使用了。

答案 4 :(得分:0)

我想最简单的方法是使用ContentFile类:

file = ContentFile('text', 'name')
my_model = MyModel()
my_model.file = file
my_model.save()