Search code examples
pythondjangopython-3.xdjango-formsdjango-testing

How can I test a form with FileField in Django?


I have this form:

# forms.py

class BookForm(forms.ModelForm):

    class Meta:
        model = Book
        fields = ['book_title', 'language', 'author', 'release_year', 'genre', 'ages', 'cover']

Type of fields: Where book_title and author are CharField, language and genre are too CharField but for them I have choice option, release_year and ages are IntegerField, and the last cover are FileField.

Choice Options:

# models.py
ENGLISH = 'english'
LANGUAGE_CHOICES = (
    (ENGLISH, 'English'),
)

ADVENTURE = 'adventure'
GENRE_CHOICES = (
    (ADVENTURE, 'Adventure'),
)

Now: I want to test this form, but I don't know how can test cover, here is my form test.

# test_forms.py
from .. import forms
from django.core.files import File


class TestBookForm:
    def test_form(self):
        form = forms.BookForm(data={})
        assert form.is_valid() is False, 'Should be invalid if no data is given'

        img = File(open('background'))

        data = {'book_title': 'Lord Of The Rings',
                'language': 'english',
                'author': 'J. R. R. Tolkien',
                'release_year': 1957,
                'genre': 'adventure',
                'ages': 16,
                'cover': img}

        form = forms.BookForm(data=data)

        assert form.is_valid() is True

I tried: from django.core.files.uploadedfile import SimpleUploadedFile

img = open('background')
uploaded = SimpleUploadedFile(img.name, img.read())
{'cover': uploaded}

This is my error:

E       assert False is True
E        +  where False = <bound method BaseForm.is_valid of <BookForm bound=True, valid=False, fields=(book_title;language;author;release_year;genre;ages;cover)>>()
E        +    where <bound method BaseForm.is_valid of <BookForm bound=True, valid=False, fields=(book_title;language;author;release_year;genre;ages;cover)>> = <BookForm bound=True, valid=False, fields=(book_title;language;author;release_year;genre;ages;cover)>
.is_valid

NOTE: I use Python 3.5, Django 1.9.4 and I start test using py.test.

UPDATE: If i try open('background.jpg') don't work. Error: FileNotFoundError: [Errno 2] No such file or directory: 'background.jpg' I fix this

UPDATE 2:

I try to use mock

from django.core.files import File
import mock

file_mock = mock.MagicMock(spec=File, name='FileMock')
file_mock.name = 'test1.jpg'

{'cover': file_mock}

I try to use InMemoryUploadedFile

from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image

im = Image.new(mode='RGB', size=(200, 200))  # create a new image using PIL
im_io = BytesIO()  # a StringIO object for saving image
im.save(im_io, 'JPEG')  # save the image to im_io
im_io.seek(0)  # seek to the beginning

image = InMemoryUploadedFile(
    im_io, None, 'random-name.jpg', 'image/jpeg', None, None
)

{'cover': image}

I fix the path to my image.


Solution

  • I find the problem This is my code:

    #test_forms.py
    from .. import forms
    from django.core.files.uploadedfile import SimpleUploadedFile
    import os
    
    TEST_DIR = os.path.dirname(os.path.abspath(__file__))
    TEST_DATA_DIR = os.path.join(TEST_DIR, 'data')
    
    
    class TestBookForm:
        def test_form(self):
            form = forms.BookForm(data={})
            assert form.is_valid() is False, 'Should be invalid if no data is given'
    
            test_image_path = os.path.join(TEST_DATA_DIR, 'background.jpg')
    
            data = {'book_title': 'Lord Of The Rings',
                    'language': 'english',
                    'author': 'J. R. R. Tolkien',
                    'release_year': 1957,
                    'genre': 'adventure',
                    'ages': 16}
    
            with open(test_image_path, 'rb') as f:
                form = forms.BookForm(data=data, files={'cover': SimpleUploadedFile('cover', f.read())})
                assert form.is_valid(), 'Invalid form, errors: {}'.format(form.errors)
    

    More info in the docs