I'm trying to perform a simple test on my form to confirm that it's not valid when there is no data given and is valid when data is given.
When running tests with pytest (py.test) the test with no data works fine but I'm getting this error for the test with data present:
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'
update: collected more specific errors using:
assert form.errors == {}, 'should be empty'
errors:
{'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.']}
how to address them?
update 2: as Nadège suggested I modified data to include published and read_time, changed category into a list and created a user without mixer.
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],}
There is still error regarding the 'author':
{'author': ['Select a valid choice. That choice is not one of the available choices.']}
update 3: for some reason 'author' had to be provided as an id, the working code for this test looks like this:
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'