msln
msln

Reputation: 1523

Django - how to write test for DRF ImageField

I have the following serializer:

from rest_framework.serializers import Serializer, ImageField

class MySerializer(Serializer):
    avatar = ImageField()

how can I write a unit test for it? I used the Django TestCase, but it raises an error.

from django.test import TestCase

class MySerializerTest(TestCase):

    def setUp(self):
        self.data = {}
        ...

    def test_image(self):
        import tempfile
        self.data['avatar'] = tempfile.NamedTemporaryFile(suffix=".jpg").file
        r_data = json.dumps(self.data)
        j_data = json.loads(r_data)
        serializer = MySerializer(data=j_data)
        if not serializer.is_valid():
            import pprint
            pprint.pprint(serializer.errors)
        self.assertEqual(serializer.is_valid(), True)

but it raises the following error:

TypeError: Object of type 'BufferedRandom' is not JSON serializable

What's my mistake? how can I write a test for image field?

Upvotes: 1

Views: 1771

Answers (2)

Davit Tovmasyan
Davit Tovmasyan

Reputation: 3588

I suggest to use SimpleUploadedFile class from django and create and image using Pillow package. See the example below.

from PIL import Image

from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.utils.six import BytesIO


class MySerializerTest(TestCase):
    ...

    def test_image(self):
        image = BytesIO()
        Image.new('RGB', (100, 100)).save(image, 'JPEG')
        image.seek(0)

        self.data['avatar'] = SimpleUploadedFile('image.jpg', image.getvalue())
        serializer = MySerializer(data=self.data)
        self.assertEqual(serializer.is_valid(), True)

Upvotes: 5

A. J. Parr
A. J. Parr

Reputation: 8026

Usually when you upload a file you would use the multipart request format, and the view would convert the image into an InMemoryUploadedFile object, and that gets passed into your serializer

So to fix your tests I'd recommend trying:

from PIL import Image
from tempfile import NamedTemporaryFile
from django.conf.files.uploadedfile import InMemoryUploadedFile

...

def test_image(self):
    image = Image.new("RGB", (100, 100))
    with NamedTemporaryFile(suffix=".png", mode="w+b") as tmp_file:
        image.save(tmp_file, format="png")
        tmp_file.seek(0)
        byio = BytesIO(temp_file.read())
        inm_file = InMemoryUploadedFile(
            file=byio,
            field_name="avatar",
            name="testImage.png",
            content_type="image/png",
            size=byio.getbuffer().nbytes,
            charset=None,
        )

        self.data['avatar'] = inm_file
        serializer = MySerializer(data=self.data)
        if not serializer.is_valid():
            import pprint
            pprint.pprint(serializer.errors)
        self.assertEqual(serializer.is_valid(), True)

What this is doing is:

  1. Create an image in memory using PIL.Image
  2. Create a NamedTemporaryFile to store the Image data
  3. Take the NamedTemporaryFile and read into a InMemoryUploadedFile
  4. Pass this InMemoryUploadedFile into the serializer

Upvotes: 0

Related Questions