简体   繁体   English

使用 ImageField 对 Django ModelForm 进行单元测试,测试显示无效表单

[英]Unit testing Django ModelForm with ImageField, tests show invalid form

Trying to test a Django ModelForm, but the test cases are failing.尝试测试 Django ModelForm,但测试用例失败。 Passing the required data but, it still shows "The image field is required" and tests show invalid form.传递所需的数据,但它仍然显示“需要图像字段”并且测试显示无效的表单。

models.py模型.py

# models.py

import sys

from PIL import Image
from io import BytesIO

from django.contrib.auth.models import User
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db import models
from django.utils.translation import ugettext as _


class ProfileImage(models.Model):
    user = models.OneToOneField(User, verbose_name=_("user"), on_delete=models.CASCADE)
    image = models.ImageField(upload_to="profile")
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.username

    def save(self, *args, **kwargs):
        if not self.id:
            uploaded_image = Image.open(self.image)
            rgb_image = uploaded_image.convert("RGB")
            output = BytesIO()
            image_resized = rgb_image.resize((300, 300))
            image_resized.save(output, format="JPEG", quality=100)
            output.seek(0)
            self.image = InMemoryUploadedFile(
                output, "ImageField", "{}.jpg".format(self.image.name.split('.')[0]),
                "image/jpeg", sys.getsizeof(output), None
            )
        super().save(*args, **kwargs)

forms.py表格.py

# forms.py

from PIL import Image

from django import forms
from django.forms.utils import ErrorList
from django.utils.translation import ugettext as _

from .models import (
    ProfileImage,
)


class ProfileImageForm(forms.ModelForm):
    class Meta:
        model = ProfileImage
        fields = ["image"]

    def clean(self):
        image = self.cleaned_data.get("image")
        if image:
            image = Image.open(image)
            width, height = image.size
            image_format = image.format
            if image_format not in ("PNG", "JPEG", "MPO"):
                msg = _("Unsupported image type. Please upload a *png or *jpg image.")
                self._errors["image"] = ErrorList([msg])
                del image

            if width < 300 or height < 300:
                msg = _("Image is too small! Please upload image of size 300px x 300px or More.")
                self._errors["image"] = ErrorList([msg])
                del image
        return self.cleaned_data

test_forms.py test_forms.py

# test_forms.py

import os
import tempfile

from mixer.backend.django import mixer
import numpy
from PIL import Image

from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase

from base.models import (
    ProfileImage
)
from base.forms import (
    ProfileImageForm,
)


# utils functions
def get_test_image(height=100, width=100):
    """
    Generate image for test purpose

    Args:
        height(int): image height
        width(int): image width

    Returns:
        image(str): image path
    """

    image = tempfile.NamedTemporaryFile(suffix=".png", dir=settings.MEDIA_ROOT, delete=True).name
    imarray = numpy.random.rand(height, width, 3) * 255
    im = Image.fromarray(imarray.astype("uint8")).convert("RGBA")
    im.save(image)
    return image


def delete_test_image(image):
    """
    Delete image generated for test purpose

    Args:
        image(str): image path

    Returns:

    """

    if os.path.exists(image):
        os.remove(image)


class TestFormData(TestCase):
    def setUp(self):
        self.standard_profile_test_image = get_test_image(300, 300)

    # 1st way, Fails
    def test_image_form_valid_1(self):
        image_path = self.standard_profile_test_image
        profile_img_instance = mixer.blend(ProfileImage, image=image_path)
        image = profile_img_instance.image
        form_data = {"image": image}
        form = ProfileImageForm(form_data)
        self.assertTrue(form.is_valid())
        delete_test_image(profile_img_instance.image.path)

    # 2nd way, Fails
    def test_image_form_valid_2(self):
        image_path = self.standard_profile_test_image
        with open(image_path, "rb") as f:
            file_data = f.read()
            file_name = f.name
        form_data = {"image": SimpleUploadedFile(file_name, file_data)}
        form = ProfileImageForm(data=form_data)
        self.assertTrue(form.is_valid())

    def tearDown(self):
        delete_test_image(self.standard_profile_test_image)

When I ran these two tests both of them threw errors: form is invalid当我运行这两个测试时,它们都抛出了错误: form is invalid

The form shows the image field is required even though I passed the required data.表单显示the image field is required即使我传递了所需的数据。

>>> form
>>> <ProfileImageForm bound=True, valid=False, fields=(image)>
>>> form.errors
>>> {'image': ['This field is required.']}
>>> form.non_field_errors()
>>> []

当使用带有文件字段的表单时,POST 数据(非文件字段)应该是第一个参数,FILE 数据(文件字段)应该是第二个参数

form = ProfileImageForm({}, {"image": image})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM