115
For future users, I’ve solved the problem.
You can mock an ImageField
with a SimpleUploadedFile
instance.
test.py
from django.core.files.uploadedfile import SimpleUploadedFile
newPhoto.image = SimpleUploadedFile(name='test_image.jpg', content=open(image_path, 'rb').read(), content_type='image/jpeg')
31
You can use a temporary file, using tempfile
. So you don’t need a real file to do your tests.
import tempfile
image = tempfile.NamedTemporaryFile(suffix=".jpg").name
If you prefer to do manual clean-up, use tempfile.mkstemp()
instead.
- [Django]-Django related_name for field clashes
- [Django]-Why is logged_out.html not overriding in django registration?
- [Django]-Django Admin Form for Many to many relationship
26
Tell the mock library to create a mock object based on Django’s File class
import mock
from django.core.files import File
file_mock = mock.MagicMock(spec=File, name='FileMock')
and then use in your tests
newPhoto.image = file_mock
- [Django]-Use Python standard logging in Celery
- [Django]-Django celery task: Newly created model DoesNotExist
- [Django]-ValueError: The field admin.LogEntry.user was declared with a lazy reference
25
If you don’t want to create an actual file in the filesystem, you can use this 37-byte GIF instead, small enough to a be a bytes literal in your code:
from django.core.files.uploadedfile import SimpleUploadedFile
small_gif = (
b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x00\x00\x00\x21\xf9\x04'
b'\x01\x0a\x00\x01\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02'
b'\x02\x4c\x01\x00\x3b'
)
uploaded = SimpleUploadedFile('small.gif', small_gif, content_type='image/gif')
- [Django]-Django staticfiles not found on Heroku (with whitenoise)
- [Django]-Pass request context to serializer from Viewset in Django Rest Framework
- [Django]-Sort order of Django Admin records
13
Solution:
from StringIO import StringIO
# in python 3: from io import StringIO
from PIL import Image
from django.core.files.base import File
And create a static method in your TestCase class:
@staticmethod
def get_image_file(name='test.png', ext='png', size=(50, 50), color=(256, 0, 0)):
file_obj = StringIO()
image = Image.new("RGB", size=size, color=color)
image.save(file_obj, ext)
file_obj.seek(0)
return File(file_obj, name=name)
Example:
instance = YourModel(name=value, image=self.get_image_file())
- [Django]-You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application
- [Django]-Prepopulate Django (non-Model) Form
- [Django]-What is the difference between null=True and blank=True in Django?
3
You can do a few additional things to (1) avoid having to keep a dedicated test image around, and (2) ensure that all test files created during testing are deleted right after:
import shutil
import tempfile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings
MEDIA_ROOT = tempfile.mkdtemp()
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
class MyTest(TestCase):
@classmethod
def tearDownClass(cls):
shutil.rmtree(MEDIA_ROOT, ignore_errors=True) # delete the temp dir
super().tearDownClass()
def test(self):
img = SimpleUploadedFile('test.jpg', b'whatevercontentsyouwant')
# ^-- this will be saved in MEDIA_ROOT
# do whatever ...
- [Django]-How to resize an ImageField image before saving it in python Django model
- [Django]-HTML – How to do a Confirmation popup to a Submit button and then send the request?
- [Django]-Factory-boy create a list of SubFactory for a Factory
2
For someone to try upload-image test with python 3.xx
I fix little with Maxim Panfilov’s excellent answer to make more dummy image with independent name.
from io import BytesIO
from PIL import Image
from django.core.files.base import File
#in your TestCase class:
class TestClass(TestCase):
@staticmethod
def get_image_file(name, ext='png', size=(50, 50), color=(256, 0, 0)):
file_obj = BytesIO()
image = Image.new("RGBA", size=size, color=color)
image.save(file_obj, ext)
file_obj.seek(0)
return File(file_obj, name=name)
def test_upload_image(self):
c= APIClient()
image1 = self.get_image('image.png')
image2 = self.get_image('image2.png')
data =
{
"image1": iamge1,
"image2": image2,
}
response = c.post('/api_address/', data )
self.assertEqual(response.status_code, 201)
- [Django]-Render HTML to PDF in Django site
- [Django]-Annotating a Sum results in None rather than zero
- [Django]-Troubleshooting Site Slowness on a Nginx + Gunicorn + Django Stack
1
My approach how to test model with no intention to pass any useful data:
from django.core.files import File
SomeModel.objects.create(image=File(file=b""))
- [Django]-What is the max size of 'max_length' in Django?
- [Django]-Any way to make {% extends '…' %} conditional? – Django
- [Django]-Django – Login with Email
1
I want to offer another testing option, which does not require the presence of a file on the server or local machine. Perhaps it will seem interesting to someone and will be useful in the future.
from .models import Photo
from django.core.files.uploadedfile import SimpleUploadedFile
import requests # pip install requests
from io import BytesIO
from PIL import Image
class PhotoTestCase(TestCase):
@classmethod
def setUpTestData(cls):
url = "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" # for example
response = requests.get(url)
im = Image.open(BytesIO(response.content))
im_bytes = BytesIO()
im.save(fp=im_bytes, format="PNG", quality=100)
content = im_bytes.getvalue()
newPhoto = Photo()
newPhoto.image = SimpleUploadedFile(
name='test_image.png',
content=content,
content_type='image/jpeg')
newPhoto.save()
def test_add_photo(self):
photo_object = Photo.objects.first()
self.assertEqual(Photo.objects.count(), 1)
photo_object.image.delete() # It is mandatory that the file is not saved on the HDD (SSD)
- [Django]-Django template can't loop defaultdict
- [Django]-What is pip install -q -e . for in this Travis-CI build tutorial?
- [Django]-What is the difference render() and redirect() in Django?
0
If you use Factory Boy to generate your test data, that library handles this situation with an ImageField factory.
Here is a complete example. I’m assuming that all of these files are in the same Django app.
models.py example:
from django.db import models
class YourModel(models.Model):
image = models.ImageField(upload_to="files/")
factories.py example:
import factory
from . import models
class YourModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.YourModel
image = factory.Django.ImageField()
tests.py example:
from django import test
from . import factories
class YourModelTests(test.TestCase):
def test_image_model(self):
yourmodel = factories.YourModelFactory()
self.assertIsNotNone(yourmodel.image)
- [Django]-Pycharm error Django is not importable in this environment
- [Django]-Pass request context to serializer from Viewset in Django Rest Framework
- [Django]-Django – how to create a file and save it to a model's FileField?