Django表单测试失败

时间:2017-07-28 09:14:42

标签: 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

my models.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)

my forms.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']

test_forms.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建议我修改数据以包括已发布和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':['选择一个有效的选择。那个选择不是其中之一   可供选择。']}

更新3: 由于某种原因,'author'必须作为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'

1 个答案:

答案 0 :(得分:2)

好的,当你有一个无效的表格时,首先要检查原因,所以表格的错误。有了这些新信息,我们可以解决每个问题。 您的表单有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的新问题ForeignKey