Django form test fails

Viewed 1386

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'
1 Answers
Related