在 Django 中对 FileField 进行单元测试的干净方法是什么?

新手上路,请多包涵

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

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

提前致谢

PS:我的问题几乎是 Django test FileField using test fixtures 的副本,但没有公认的答案。只是想重新询问是否有关于此主题的新内容。

原文由 luc 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 465
2 个回答

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

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

如果在测试模型的保存方法后实际上不需要对该文件执行任何操作,我建议使用 python 的优秀 Mock 库 来完全伪造 File 实例(即类似于 mock_file = Mock(spec=django.core.files.File); mock_file.read.return_value = "fake file contents" ) 这样您就可以完全避免更改文件处理逻辑。 Mock 库有几种方法可以在测试方法中 全局修补 Django 的 File 类,这将尽可能简单。

如果您需要一个真实的文件(即作为测试的一部分,使用外部脚本处理等),您可以使用类似于 Mirko 示例的东西,并在确保将其存储在适当的地方后创建一个 File 对象- 以下是三种方法:

  • 让您的测试 settings.MEDIA_ROOT 指向临时目录(请参阅 Python 临时文件 模块的 mkdtemp 函数)。只要您有一个单独的 STATIC_ROOT 类的东西,它就可以正常工作,您可以将其用于作为源代码一部分的媒体文件。
  • 使用自定义 存储管理器
  • 在每个 File 实例上手动设置文件路径,或者使用自定义 upload_to 函数指向测试设置/拆卸过程清除的某个位置,例如 MEDIA_ROOT 下的测试子目录。

编辑: 模拟对象库是 python 3.3 版中的新内容。对于较旧的 python 版本,请检查 Michael Foord 的版本

原文由 Chris Adams 发布,翻译遵循 CC BY-SA 3.0 许可协议

Django 提供了一个很好的方法来做到这一点——使用 SimpleUploadedFileTemporaryUploadedFileSimpleUploadedFile 如果您只需要存储一些哨兵数据,通常是更简单的选择:

 from django.core.files.uploadedfile import SimpleUploadedFile

my_model.file_field = SimpleUploadedFile(
    "best_file_eva.txt",
    b"these are the file contents!"   # note the b in front of the string [bytes]
)

这是 django 的神奇功能之一——不会出现在文档中 :)。然而,它在 这里 被引用并 在这里 实现。

限制

请注意,您只能将 bytes 放入 SimpleUploadedFile 因为它是在幕后使用 BytesIO 实现的。如果您需要更真实的、类似文件的行为,您可以使用 TemporaryUploadedFile

对于 Python 2

如果 您卡在 python 2 上,请跳过内容中的 b 前缀:

 my_model.file_field = SimpleUploadedFile(
    "best_file_eva.txt",
    "these are the file contents!" # no b
)

原文由 waterproof 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题