1

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?

Davit Tovmasyan
  • 3,238
  • 2
  • 20
  • 36
msln
  • 1,318
  • 2
  • 19
  • 38

2 Answers2

5

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)
Thomas W
  • 14,757
  • 6
  • 48
  • 67
Davit Tovmasyan
  • 3,238
  • 2
  • 20
  • 36
0

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
A. J. Parr
  • 7,731
  • 2
  • 31
  • 46
  • it raises an error: "TypeError: a bytes-like object is required, not 'InMemoryUploadedFile'" – msln May 28 '19 at 12:09