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?
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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With