0

My django.test Client returns a response with status code, 200, when I made a post request instead of redirecting with a status code, 302.

I am using Django 2.2.4 with Python 3.7.3.

No login is required (as addressed by Why does Django Redirect Test Fail?) neither does setting the follow and secure parameters to True (as addressed by Django test client POST command not registering through 301 redirect)

I noticed that the same problem affects my update view. It doesn't redirect when I call the Django Test Client with a put method. (I didn't include this code to avoid verbosity).

Finally, I noticed that the page redirect works when I python manage.py runserver and then visit the page to create a new Book instance.

Here's the test:

from django.test import TestCase, Client
from django.urls import reverse
...

class TestDashboardViews(TestCase):
    def setUp(self):
        self.client = Client()
        self.book_list_url = reverse("dashboard-home")
        self.book_create_url = reverse("dashboard-upload-book")
        self.another_demo_book_kwargs = {
            "title": "Demo Title",
            "author": "Demo Author",
            "subject": "Another Demo Subject",
            "details": "Another Demo Details",
            "file": "path/to/another/demo/file"
        }
        ...

    def test_book_create_view_using_post_method(self):
        response = self.client.post(self.book_create_url, self.another_demo_book_kwargs)

        self.assertRedirects(response, self.book_list_url)
        ...

Here's the affected view:

class BookCreateView(CreateView):
    model = Book
    fields = ['title', 'author', 'subject', 'details', 'file']
    success_url = reverse_lazy("dashboard-home")

Here's the model:

from django.db import models
from django.utils.text import slugify


class Book(models.Model):
    title = models.CharField(max_length=50)
    slug = models.SlugField()
    author = models.CharField(max_length=100)
    subject = models.CharField(max_length=50)
    details = models.CharField(max_length=255)

    def author_title_path(self, filename):
        return "files/{author}/{filename}".format(author=slugify(self.author), filename=filename)

    file = models.FileField(upload_to=author_title_path)

    def save(self, *args, **kwargs):
        title_by_author = "{title} by {author}".format(title=self.title, author=self.author)
        self.slug = slugify(title_by_author)
        super().save(*args, **kwargs)

and here are my urls:

from django.urls import path
from dashboard.views import BookListView, BookCreateView, BookUpdateView, BookDeleteView

urlpatterns = [
    path("", BookListView.as_view(), name="dashboard-home"),
    path("add_book/", BookCreateView.as_view(), name="dashboard-upload-book"),
    path("edit_book/<slug>/", BookUpdateView.as_view(), name="dashboard-edit-book"),
    path("delete_book/<slug>/", BookDeleteView.as_view(), name="dashboard-delete-book")
]

My test fails with this error:

...
AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)
...

Please, help.

  • Your form is presumably not valid. You should examine the response to find out why; most likely, the value for `file` is not correct (it should be an actual file, not a path). – Daniel Roseman Aug 15 '19 at 12:08
  • Likely it's not valid because you're not uploading a file. See [this question](https://stackoverflow.com/questions/11170425/how-to-unit-test-file-upload-in-django) to learn how to upload files in a unit test. – dirkgroten Aug 15 '19 at 13:09
  • Thank you @DanielRoseman. The problem was truly with the file. – Kingdom Coder Aug 17 '19 at 16:29
  • Your link had the solution I needed @dirkgroten. Opening the file inside a `with` statement and passing the open file as the file parameter was the answer. Thank you. – Kingdom Coder Aug 17 '19 at 16:31

1 Answers1

1

Daniel Roseman and dirkgroten helped identify the problem in the comments.

I recommend checking out the question dirkgroten refered to (how to unit test file upload in django)

The problem was with the file field in the self.another_demo_book_kwargs created in the setup of the test.

The file field expects an actual file, not just a path.

This:

self.another_demo_book_kwargs = {
            "title": "Demo Title",
            "author": "Demo Author",
            "subject": "Another Demo Subject",
            "details": "Another Demo Details",
            "file": "path/to/another/demo/file"
        }

should be replaced with this:

with open(ABSOLUTE_FILE_PATH) as file_object:
            data = {
                "title": "Demo Title",
                "author": "Demo Author",
                "subject": "Another Demo Subject",
                "details": "Another Demo Details",
                "file": file_object
            }
            response = self.client.post(self.book_create_url, data)