我正在尝试对我的表单执行一个简单的测试,以确认在没有给出数据时它是无效的,并且在给出数据时有效。
当使用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'
答案 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
。