Django 表单测试失败

标签 django django-forms pytest django-testing

我正在尝试对我的表单执行一个简单的测试,以确认它在没有提供数据时无效,而在提供数据时有效。

当使用 pytest (py.test) 运行测试时,没有数据的测试工作正常,但我在有数据的测试中遇到此错误:

AssertionError: Should be valid if data is given
E       assert False is True
E        +  where False = <bound method BaseForm.is_valid of <PostForm bound=True, valid=False, fields=(title;content;author;image;published;draft;category;read_time)>>()
E        +    where <bound method BaseForm.is_valid of <PostForm bound=True, valid=False, fields=(title;content;author;image;published;draft;category;read_time)>> = <PostForm bound=True, valid=False, fields=(title;content;author;image;published;draft;category;read_time)>.is_valid

posts/tests/test_forms.py:21: AssertionError

我的模型.py:

from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.db.models.signals import pre_save
from django.utils import timezone

from django.utils.text import slugify
from .utils import read_time

class Category(models.Model):
    name = models.CharField(max_length=120, unique=True)
    timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated = models.DateTimeField(auto_now_add=False, auto_now=True)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.id: # to prevent changing slug on updates
            self.slug = slugify(self.name)
        return super(Category, self).save(*args, **kwargs)

def upload_location(instance, filename):
    return '%s/%s'%(instance.id, filename)

class PostManager(models.Manager):
    def active(self):
        return super(PostManager, self).filter(draft=False, published__lte=timezone.now())

class Post(models.Model):
    title = models.CharField(max_length=120)
    slug = models.SlugField(unique=True)
    content = models.TextField()
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    image = models.ImageField(
        upload_to=upload_location,
        null=True,
        blank=True)
    timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated = models.DateTimeField(auto_now_add=False, auto_now=True)
    published = models.DateField(auto_now=False, auto_now_add=False)
    draft = models.BooleanField(default=False)
    category = models.ManyToManyField(Category)
    read_time = models.IntegerField(default=0)
    objects = PostManager()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('posts:detail', kwargs={'pk': self.pk})

    def save_no_img(self):
        self.image = None
        return super(Post, self).save()


def create_slug(instance, new_slug=None):
    slug = slugify(instance.title)
    if new_slug is not None:
        slug = new_slug
    qs = Post.objects.filter(slug=slug).order_by("-id")
    exists = qs.exists()
    if exists:
        new_slug = "%s-%s" %(slug, qs.first().id)
        return create_slug(instance, new_slug=new_slug)
    return slug


def pre_save_post_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = create_slug(instance)
    html_content = instance.content
    instance.read_time = read_time(html_content)

pre_save.connect(pre_save_post_receiver, sender=Post)

我的表格.py:

from django import forms
from .models import Post
from pagedown.widgets import PagedownWidget

class PostForm(forms.ModelForm):
    published = forms.DateField(widget=forms.SelectDateWidget)
    content = forms.CharField(widget=PagedownWidget())
    class Meta:
        model = Post
        # fields = ['author', 'title', 'content', 'image', 'draft', 'published', 'category']
        exclude = ['objects', 'updated', 'timestamp', 'slug']

测试表格.py:

import pytest
from .. import forms
from posts.models import Category
from mixer.backend.django import mixer
pytestmark = pytest.mark.django_db


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

    def test_not_empty_form(self):
        staff_user = mixer.blend('auth.User', is_staff=True)
        category = mixer.blend('posts.Category')
        data={'content': 'some content',
            'author': staff_user,
            'title': 'some title',
            'category': category,}
        form = forms.PostForm(data=data)
        assert form.is_valid() is True, 'Should be valid if data is given'

更新: 使用以下方法收集更具体的错误:

assert form.errors == {}, 'should be empty'

错误:

{'author': ['Select a valid choice. That choice is not one of the 
available choices.'],
'category': ['Enter a list of values.'],
'published': ['This field is required.'],
'read_time': ['This field is required.']}

如何解决它们?

更新 2: 按照 Nadège 的建议,我修改了数据以包含 published 和 read_time,将类别更改为列表并创建了一个没有混音器的用户。

staff_user = User.objects.create_superuser(is_staff=True,
                                        email='oo@gm.com',
                                        username='staffuser',
                                        password='somepass')
category = mixer.blend('posts.Category')
today = date.today()
data={'content': 'some content',
    'author': staff_user,
    'title': 'some title',
    'published': today,
    'read_time': 1,
    'category': [category],}

关于“作者”仍然有错误:

{'author': ['Select a valid choice. That choice is not one of the available choices.']}

更新 3: 由于某种原因,“作者”必须作为 id 提供,此测试的工作代码如下所示:

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

    def test_not_empty_form(self):
        staff_user = mixer.blend('auth.User')
        category = mixer.blend('posts.Category')
        today = date.today()
        data={'content': 'some content',
            'author': staff_user.id,
            'title': 'some title',
            'published': today,
            'read_time': 1,
            'category': [category],}
        form = forms.PostForm(data=data)
        assert form.errors == {}, 'shoud be empty'
        assert form.is_valid() is True, 'Should be valid if data is given'

最佳答案

好吧,当你有一个无效的表格时,首先要检查为什么,所以表格的错误。有了这些新信息,我们就可以解决每个问题。 您的表单有 4 个验证错误。最后两个非常简单。

'published': ['This field is required.'],
'read_time': ['This field is required.']

您表单中的那两个字段是必填字段,但您没有填写它们。 所以你有两个选择,

  • 在您提供给表单的 data 中为这些字段添加一个值
  • 从表单中删除字段:将它们添加到exclude

您还可以像这样设置发布字段为非必填字段:

published = forms.DateField(widget=forms.SelectDateWidget, required=False)

对于read_time,该字段是否必填,取决于模型中对应的字段。如果模型字段不可为空,则根据需要设置表单中的字段。

接下来是

'category': ['Enter a list of values.']

您提供了一个值,但类型不是预期的。 category 在你的模型中是 ManyToMany 所以你不能只给出一个类别,它必须是一个列表(即使它只有一个元素!)

'category': [category],

最后是作者,

'author': ['Select a valid choice. That choice is not one of the available choices.']

您也提供了一个无效的值。验证未将该值识别为正确的 auth.User。我不熟悉 Mixer,所以可能会问一个新问题,专门关于 Mixer 和 Django Forms with a ForeignKey

关于Django 表单测试失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45369483/

相关文章:

python - 检索人员的最新对象

django - 如何按字母顺序对模板中的对象列表进行排序?

django - 如何制作 "workflow"表格

django - 保存模型 int() 参数必须是字符串或数字,而不是 'tuple'

python - 使用 pytest.fixture 返回模拟对象的正确方法

python - 如何从异步 pytest 函数测试异步单击命令?

django - 在模板中声明变量

django - 如何使用不同的序列化程序反序列化 POST 请求

Django 密码重置。不发送邮件

python - 使用 pytest 测试类方法