Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test Django's UpdateView?

Tags:

python

django

As a simplified example, I've written an UpdateView for a Book model, as well as a ListView to redirect to upon success:

from django.urls import reverse
from django.views.generic import ListView
from django.views.generic.edit import UpdateView
from .models import Book


class BookUpdate(UpdateView):
    model = Book
    fields = ['title', 'author']


class BookList(ListView):
    model = Book

The Book model is defined as

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100, blank=True)

    def get_absolute_url(self):
        return reverse('books-list')

where urls.py is

from django.urls import path
from books.views import BookUpdate, BookList


urlpatterns = [
    path('books/', BookList.as_view(), name='books-list'),
    path('book/<int:pk>/', BookUpdate.as_view(), name='book-update')
]

In books/tests.py I've tried to write the following test:

class BookUpdateTest(TestCase):
    def test_update_book(self):
        book = Book.objects.create(title='The Catcher in the Rye')

        response = self.client.post(
            reverse('book-update', kwargs={'pk': book.id}), 
            {'author': 'J.D. Salinger'})

        self.assertEqual(response.status_code, 200)

        book.refresh_from_db()
        self.assertEqual(book.author, 'J.D. Salinger')

However, this test fails because the book's author appears not to be updated after the POST request, even after refreshing from the database:

FAIL: test_update_book (books.tests.BookUpdateTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/Scratch/book_project/books/tests.py", line 46, in test_update_book
    self.assertEqual(book.author, 'J.D. Salinger')
AssertionError: '' != 'J.D. Salinger'
+ J.D. Salinger

On the other hand, if I run the development server and fill out the fields manually, everything seems to work as expected. How can I write a unit test for the UpdateView which captures the user updating the fields, submitting the form, and making changes to the corresponding objects?

like image 716
Kurt Peek Avatar asked Feb 15 '18 19:02

Kurt Peek


1 Answers

It seems that if you POST to a form, you have to post all required fields, not just the ones you are updating - even if the required field of the underlying model already has a value. Also, the status code returned upon a successful update is 302 'Found', not 200 'OK'. So the following test passes:

class BookUpdateTest(TestCase):
    def test_update_book(self):
        book = Book.objects.create(title='The Catcher in the Rye')

        response = self.client.post(
            reverse('book-update', kwargs={'pk': book.id}), 
            {'title': 'The Catcher in the Rye', 'author': 'J.D. Salinger'})

        self.assertEqual(response.status_code, 302)

        book.refresh_from_db()
        self.assertEqual(book.author, 'J.D. Salinger')
like image 136
Kurt Peek Avatar answered Sep 25 '22 18:09

Kurt Peek