在 django 中对 FileField 进行单元测试的干净方法是什么?
我有一个带有 FileField 的模型。我想对其进行单元测试。 django 测试框架有很好的方法来管理数据库和电子邮件。 FileFields 有类似的东西吗?
我如何确保单元测试不会污染真正的应用程序?
提前致谢
PS:我的问题几乎是 使用测试装置的 Django test FileField 但它没有公认的答案。只是想再次询问这个主题是否有新内容。
I have a model with a FileField. I want to unittest it. django test framework has great ways to manage database and emails. Is there something similar for FileFields?
How can I make sure that the unittests are not going to pollute the real application?
Thanks in advance
PS: My question is almost a duplicate of Django test FileField using test fixtures but it doesn't have an accepted answer. Just want to re-ask if something new on this topic.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
Django 提供了一个很好的方法来做到这一点 - 使用
SimpleUploadedFile
或TemporaryUploadedFile
。如果您需要存储的只是一些哨兵数据,那么 SimpleUploadedFile 通常是更简单的选择:这是 django 的神奇功能之一,但不会在文档中显示:)。然而,它被引用这里 并在此处实现。
限制
请注意,您只能将
bytes
放入SimpleUploadedFile
中,因为它是在幕后使用BytesIO
实现的。如果您需要更真实的、类似文件的行为,您可以使用 TemporaryUploadedFile。对于 Python 2
如果您被困在 python 2 上,请跳过内容中的
b
前缀:Django provides a great way to do this - use a
SimpleUploadedFile
or aTemporaryUploadedFile
.SimpleUploadedFile
is generally the simpler option if all you need to store is some sentinel data:It's one of django's magical features-that-don't-show-up-in-the-docs :). However it is referred to here and implemented here.
Limitations
Note that you can only put
bytes
in aSimpleUploadedFile
since it's implemented usingBytesIO
behind the scenes. If you need more realistic, file-like behavior you can useTemporaryUploadedFile
.For Python 2
If you're stuck on python 2, skip the
b
prefix in the content:有几种方法可以解决这个问题,但它们都很丑陋,因为单元测试应该是隔离的,但文件都是关于持久更改的。
我的单元测试不在具有生产数据的系统上运行,因此每次运行后使用 git reset --hard 之类的东西重置上传目录很容易。从某些方面来说,这种方法是最好的,因为它不涉及任何代码更改,并且只要您从良好的测试数据开始,就保证可以工作。
如果在测试模型的保存方法后实际上不需要对该文件执行任何操作,我建议使用 python 的优秀 模拟库 来完全伪造
File
实例(即类似于mock_file = Mock(spec=django.core.files.File); mock_file .read.return_value =“假文件内容”
),这样您就可以完全避免更改文件处理逻辑。 Mock 库有多种方法全局修补 Django 的 File 类 在测试方法中,就像这样简单会得到。如果您需要一个真实的文件(即作为测试的一部分,使用外部脚本进行处理等),您可以使用类似于 Mirko 示例的内容并创建一个 文件对象 确保将其存储在适当的位置后 - 以下是三种方法:
settings.MEDIA_ROOT
指向临时目录(请参阅 Python tempfile< /a> 模块的mkdtemp
函数)。只要您有一个单独的STATIC_ROOT
之类的东西,用于作为源代码一部分的媒体文件,这种方法就可以正常工作。MEDIA_ROOT
下的测试子目录。编辑:模拟对象库是Python 3.3版本中的新功能。对于较旧的 python 版本,请检查 Michael Foord 的版本
There are several ways you could tackle this but they're all ugly since unit tests are supposed to be isolated but files are all about durable changes.
My unit tests don't run on a system with production data so it's been easy to simply reset the upload directory after each run with something like
git reset --hard
. This approach is in some ways the best simply because it involves no code changes and is guaranteed to work as long as you start with good test data.If you don't actually need to do anything with that file after testing your model's save method, I'd recommend using python's excellent Mock library to completely fake the
File
instance (i.e. something likemock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents"
) so you can completely avoid changes to your file handling logic. The Mock library has a couple of ways to globally patch Django's File class within a test method which is about as easy as this will get.If you need to have a real file (i.e. for serving as part of a test, processing with an external script, etc.) you can use something similar to Mirko's example and create a File object after making sure it'll be stored somewhere appropriate - here are three ways to do that:
settings.MEDIA_ROOT
point to a temporary directory (see the Python tempfile module'smkdtemp
function). This works fine as long as you have something like a separateSTATIC_ROOT
which you use for the media files which are part of your source code.MEDIA_ROOT
.Edit: mock object library is new in python version 3.3. For older python versions check Michael Foord's version
我通常使用 doctest 测试模型中的文件字段,
如果需要,我还会使用测试客户端测试文件上传。
至于固定装置,我只需在修改固定装置中的路径后将所需的文件复制到测试文件夹中即可。
例如,
在包含文件字段指向名为“audio”的目录的模型的装置中,将“audio”:“audio/audio.wav”替换为“audio”:“audio/test/audio.wav”。
现在您所要做的就是将测试文件夹以及必要的文件复制到测试设置中的“音频”中,然后在拆卸中将其删除。
这不是我认为的最干净的方式,但这就是我所做的。
I normally test filefields in models using doctest
If I need to I also test file uploads with test clients.
As for fixtures, I simply copy the files i need in a test folder, after modifying the paths in the fixture.
e.g.
In a fixture containing models with filefiels pointing to a directory named "audio", you replace "audio": "audio/audio.wav" with "audio": "audio/test/audio.wav" .
Now all you have to do is copy the test folder, with the necessary files, in "audio" in the test setUp and then delete it in tearDown.
Not the cleanest way ever i think, but that's what i do.
如果您只想创建一个需要 FileField 的对象并且不想使用此字段,那么您只需传递任何(现有或不存在)相对路径,如下所示:
然后就可以使用了。
If you just want to create an object that requires FileField and don't want to use this field then you can just pass any (existing or not) relative path like this:
Then it's ready for use.
我想最简单的方法是使用 ContentFile 类:
I guess that easiest way is to use ContentFile class:
有一些方法可以模拟存储。
阅读 django 源代码后,以下是我的实现,以避免将文件上传到 s3,无论使用默认存储还是在文件字段或图像字段中分配存储。
通过继承CustomBaseTestCase类,您可以更改存储以避免将文件上传到任何服务器
There is some way to mock storage.
After reading django source code, the below is my implementation to avoid uploading file to s3 regardless of using default storage or assigning the storage in filefield or imagefield.
With inheriting CustomBaseTestCase class, you can change your storage to avoid uploading files to any server