Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django 模拟自定义文件存储后端_Django_Unit Testing_Amazon S3 - Fatal编程技术网

Django 模拟自定义文件存储后端

Django 模拟自定义文件存储后端,django,unit-testing,amazon-s3,Django,Unit Testing,Amazon S3,我已经创建了一个自定义文件存储后端,它使用boto调用AmazonS3并将文件存储在那里(我知道django storages也会处理这个问题,但我们遇到了一些问题)。我将其存储在utils模块中,并在我的模型中使用,如下所示: from utils.s3 import S3Storage class Photo(models.Model): image = models.ImageField(storage=S3Storage(), upload_to="images") 因此,每当使

我已经创建了一个自定义文件存储后端,它使用boto调用AmazonS3并将文件存储在那里(我知道django storages也会处理这个问题,但我们遇到了一些问题)。我将其存储在utils模块中,并在我的模型中使用,如下所示:

from utils.s3 import S3Storage

class Photo(models.Model):
  image = models.ImageField(storage=S3Storage(), upload_to="images")
因此,每当使用图像文件创建照片时,图像文件都会上载到S3存储桶

我不想在测试期间调用S3,但很难弄清楚在这种情况下要模拟什么。我无法模拟整个图像字段,因为我需要通过Tastypie测试创建模型


有什么想法吗

您可以在
S3Storage
类中模拟
\u save
方法,以避免上传到S3。您可以改用
FileSystemStorage

对于您的案例,我的解决方案如下:

import mock
from utils.s3 import S3Storage
from django.core.files.storage import FileSystemStorage


fss = FileSystemStorage()

@mock.patch.object(S3Storage, '_save', fss._save)
def test_something():
    assert True

我尝试了许多其他解决方案,比如在设置
默认文件存储中覆盖
或Manh-Tai的解决方案。所有问题都是Django在初始化时在内存中加载所有模型,这使得在设置模型属性后修改模型属性有点不直观

使用Django 2.1和Python 3进行测试:

来自unittest.mock导入MagicMock
从django.core.files.storage导入存储
从django.core.files.uploadedfile导入SimpleUploadedFile
类CreatePhotoTest(测试用例):
def测试后照片(自身):
def生成_文件名(文件名):
返回文件名
def保存(名称、内容、最大长度):
返回名称
存储\u mock=MagicMock(spec=storage,name='StorageMock')
存储\u mock.generate\u filename=生成\u filename
存储\u mock.save=MagicMock(副作用=保存)
storage_mock.url=MagicMock(name='url')
存储\u mock.url.return\u value='0http://example.com/generated_filename.png'
照片。_meta.get_字段('image')。存储=存储
img=SimpleUploadedFile('file.png',b“file\u content”,content\u type=“image/png”)
数据={
“已签署的合同”:img
}
response=self.client.post('/endpoint',data,format='multipart')
self.assertTrue(存储\u mock.save.called)
生成的\u filename=storage\u mock.save.call\u args\u list[0][0]
上传的文件=存储模拟保存调用参数列表[0][0][1]
self.assertEqual(上传的_file.name,'file.pdf')

我创建了
generate\u filename()
save()
,但如果您不想这样做,就不需要这样做。这样做只是为了尽可能多地模拟真实存储器的行为,并在测试中对其进行验证。

类似的操作可以用于pytest:

import pytest
import os
from django.core.files.storage import get_storage_class

@pytest.fixture
def mock_storage(monkeypatch):
    """
    Mocks the backend storage system by not actually accessing media
    """

    clean_name = lambda name: os.path.splitext(os.path.basename(name))[0]

    def _mock_save(instance, name, content):
        setattr(instance, f"mock_{clean_name(name)}_exists", True)
        return str(name).replace('\\', '/')

    def _mock_delete(instance, name):
        setattr(instance, f"mock_{clean_name(name)}_exists", False)
        pass

    def _mock_exists(instance, name):
        return getattr(instance, f"mock_{clean_name(name)}_exists", False)

    storage_class = get_storage_class()

    monkeypatch.setattr(storage_class, "_save", _mock_save)
    monkeypatch.setattr(storage_class, "delete", _mock_delete)
    monkeypatch.setattr(storage_class, "exists", _mock_exists)

然后,这是否会写入文件系统(在测试期间您不希望执行的其他操作)?我想您可能不希望在
save()
上发生任何事情,然后将其写入文件系统,但我认为这是可以接受的,因为它不是第三方API,我们最终会在运行测试后破坏测试环境。您也可以使用带有返回值的模拟,而不是使用真正的
\u save
方法:
@patch.object(GoogleCloudMediaStorage,'.'u save',MagicMock(返回值='/tmp/plain.pdf'))
@mock.patch.object(S3boto3存储,'.'u save',lambda self,name,content:name)
完成这项工作。