3

I have 2 models. First is House. Second is HouseImage
Therefore I have to submit the image with ForeigneKey
I can upload by using the REST normally, but failed to do unittest.
The reason why I keep doing unittest in here because I have a more specifications waiting for me and I would not do hand-test for sure.

django==1.11.5
djangorestframework==3.6.4
python3.6.2
PostgreSQL 9.6.5 on x86_64-apple-darwin14.5.0, compiled by Apple LLVM version 7.0.0 (clang-700.1.76), 64-bit

Here is my additional source code.
https://gist.github.com/elcolie/a013be9c3b7ab5f0cc130e320b19da4b

import tempfile

from PIL import Image
from django.contrib.auth.models import User
from model_mommy import mommy
from rest_framework import status
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase, APIClient

from soken_web.apps.houses.models import House


class HouseImageTest(APITestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = mommy.make(User, username='Pan')
        self.house = mommy.make(House, location="100.00, 100.00")

    def test_post_image(self):
        self.client.force_authenticate(user=self.user)

        image = Image.new('RGB', (100, 100))

        tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
        image.save(tmp_file)
        data = {
            'image': tmp_file,
            'house': self.house.id,
        }

        response = self.client.post(reverse('api:house_images-list'), data, format='multipart')

        self.assertEqual(status.HTTP_201_CREATED, response.status_code)

Problem:
Server raises appliation/json type to me

Attempts:
1. Replace format=multipart with content_type/multipart. Same error 1. User both format=mulipart and content_type/multipart. It is not permitted by DRF

Solution:
@zaidfazil Thank you very much. You are right. I have to use real-file

import tempfile

from django.conf import settings
from django.contrib.auth.models import User
from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from model_mommy import mommy
from rest_framework import status
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase, APIClient

from soken_web.apps.houses.models import House


class HouseImageTest(APITestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = mommy.make(User, username='Pan')
        self.house = mommy.make(House, location="100.00, 100.00")
        settings.MEDIA_ROOT = tempfile.mkdtemp()

    def test_post_image(self):
        file = File(open('static/rest_framework/img/grid.png', 'rb'))
        uploaded_file = SimpleUploadedFile('new_image.jpg', file.read(), content_type='multipart/form-data')
        data = {
            'image': uploaded_file,
            'houses': self.house.id,
        }

        self.client.force_authenticate(user=self.user)
        response = self.client.post(reverse('api:house_images-list'), data, format='multipart')
        response.render()

        self.assertEqual(status.HTTP_201_CREATED, response.status_code)

References:
How can I test binary file uploading with django-rest-framework's test client?
http://www.django-rest-framework.org/api-guide/testing/

joe
  • 8,383
  • 13
  • 61
  • 109
  • Did you try the solution from other answers that you link on references? Like this https://stackoverflow.com/a/30291143/4900574 or this https://stackoverflow.com/a/43212184/4900574 – amarynets Sep 20 '17 at 04:34
  • Thank you for your response. First URL I got I/O error. The next one was interrupt by zaidfazil answer and finally solve my problem. – joe Sep 20 '17 at 05:27

1 Answers1

5

You may need to convert the file into uploaded file format before posting to the url,

from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files import File

class HouseImageTest(APITestCase):

    def setUp(self):
        self.client = APIClient()
        self.user = mommy.make(User, username='Pan')
        self.house = mommy.make(House, location="100.00, 100.00")
        settings.MEDIA_ROOT = tempfile.mkdtemp()

    def test_post_image(self):

        image = Image.new('RGB', (100, 100))    
        tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
        image.save(tmp_file)

        file = File(tmp_file)
        uploaded_file = SimpleUploadedFile('new_image.jpg', file.read(), content_type='multipart/form-data')

        data = {
            'image': uploaded_file,
            'houses': self.house.id,
        }

        self.client.force_authenticate(user=self.user)
        response = self.client.post(reverse('api:house_images-list'), data, format='multipart')
        response.render()

        self.assertEqual(status.HTTP_201_CREATED, response.status_code)
zaidfazil
  • 9,017
  • 2
  • 24
  • 47
  • Same error. – joe Sep 20 '17 at 04:44
  • Did you set your `settings.MEDIA_ROOT`? – zaidfazil Sep 20 '17 at 04:45
  • Did you print out the response like `print(response.json())`, there you can see what's the error actually raising... Also, could you post the `models.py` for `House` and `HouseImage`? – zaidfazil Sep 20 '17 at 04:53
  • In your `HouseImage` model, field_name is `houses` (which is a mandatory field, ie, NOT NULL), but in your test, its `house`. Maybe that's the error is about. Change `house` => `houses` in `data`. – zaidfazil Sep 20 '17 at 05:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154842/discussion-between-sarit-and-zaidfazil). – joe Sep 20 '17 at 05:08