Youssef
Youssef

Reputation: 1495

Django - Test fails even though the link works

I found a great tutorial written with Django-1.11. But I have decided to use the current version (2.0.5) and try to adapt the tutorial. If I succeed, I would like to provide an updated version of the tutorial afterwards.

Changing some things that were deprecated, I have already done well with the help of official Django documentation. But while writing some tests, I encountered difficulties.

I don't understand why I'm getting this 404 != 200 error.

views.py

# ...
def board_topics(request, pk):
    board = get_object_or_404(Board, pk=pk)
    return render(request, "topics.html", {"board": board})

urls.py

# ...
urlpatterns = [
    path("boards/<int:pk>/", views.board_topics, name="board_topics"),
    path("home/", views.home, name="home"),
    path("admin/", admin.site.urls),
]

tests.py

# ...
class BoardTopicsTests(TestCase):
    def setUp(self):
        self.board = Board.objects.create(
            name="Django", description="Django discussion board"
        )

    # ...
    def test_board_topics_view_contains_link_back_to_homepage(self):
        board_topics_url = reverse("board_topics", kwargs={"pk": 1})
        response = self.client.get(board_topics_url)
        homepage_url = reverse("home")
        self.assertContains(
            response, 'href="{0}"'.format(homepage_url)
        )

Traceback

FAIL: test_board_topics_view_contains_link_back_to_homepage (boards.tests.BoardTopicsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../boards/tests.py", line 52, in test_board_topics_view_contains_link_back_to_homepage
self.assertContains(response, 'href="{0}"'.format(homepage_url))
...
AssertionError: 404 != 200 : 
Couldn't retrieve content: Response code was 404 (expected 200)
----------------------------------------------------------------------
Ran 7 tests in 0.038s
FAILED (failures=1)

I wonder why I'm getting this error although I can call the views. Have I written this test properly?

Upvotes: 1

Views: 756

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476719

The error is probably caused because there is no element with primary key pk=1. A database will typically store in memory an "id dispatcher". Some sort of routine that each time when an auto incrementing id is required, distributes one, and increment the counter. But note that if you later for example remove that object, and create a new one, you will not "reuse" the identifier, but simply take the next one (some databases will calculate the maximum id when they restart, and continue counting from that identifier).

Regardless how the database actually dispatches primary keys, you have no control about that procedure, hence it is unsafe to make assumptions on that.

You therefore better obtain the pk attribute of the Board object you stored:

class BoardTopicsTests(TestCase):
    def setUp(self):
        self.board = Board.objects.create(
            name="Django", description="Django discussion board"
        )

    # ...

    def test_board_topics_view_contains_link_back_to_homepage(self):
        board_topics_url = reverse("board_topics", kwargs={"pk": self.board.pk})
        response = self.client.get(board_topics_url)
        homepage_url = reverse("home")
        self.assertContains(response, 'href="{0}"'.format(homepage_url))

When you run pytest (or another testing tool), it will run tests before and after the current testcase, and you therefore do not really know what the state of the id dispatcher will be if it reaches this particular testcase.

The above is a special case of "making too much assumptions about backends". One of the ideas behind Django is to have for example an ORM that is database-invariant (to some extent). So that means that you should not make assumptions how a particular database system will work, since Django is meant to easily migrate an application from one database system to another, and keeping all the code intact (the Django ORM will for example build different queries that work on the new database system). By making such assumptions you will eventually "lock yourself in" into a specific architecture, which can be dangerous if later the needs of your application change, and a different architecture is better suited for those needs.

Upvotes: 1

Related Questions