Search code examples
djangodjango-rest-frameworkdjango-testing

I want to add a DRF API route only for testing (override_settings), getting 404


I want the following test to pass, but I am always getting a 404 Error. But I would expect the "get all" request to return all users.

import json

from django.test.utils import override_settings
from django.urls import path, include
from rest_framework import routers

from frontend.tests.mocks import views
from django.test import TestCase


app_name = 'frontend'
router = routers.SimpleRouter()
router.register('api/', views.UserModelViewSet)

urlpatterns = [
    path('', include(router.urls)),
]


@override_settings(ROOT_URLCONF=__name__)
class TestJsonSchemaSerializer(TestCase):  # APITest doesn't work either

    def test_custom_serializer(self):
        resp = self.client.get('/frontend/api/')
        self.assertEquals(resp.status_code, 200)
        print(resp.status_code, json.dumps(resp.json()))


Solution

  • A few things to note:

    If you want a route to exist/be registered ONLY when running test, you can add it conditionally. A good way to do so is to:

    • Have different settings file (settings/development.py, settings/test.py, ...)
    • Use the test settings when running tests
    • In your test settings, have a variable like IS_TEST=True
    • Then in your urls.py file, use this settings to conditionally register the view

    On top of that, as good practices, you should register your api to /api/ and your viewsets as subpaths, like /api/users/

    # Create router
    router = routers.SimpleRouter()
    
    # Register views
    router.register("users", views.UserModelViewSet, "users")
    # Conditionally register views
    if settings.IS_TEST:
        router.register("others", views.OtherViewSet, "others")
    
    # Expose the API
    app_urls = [
        path("api/", include(router.urls)),
    ]
    

    Then you can update:

    • Update your testcase to discard the override_settings
    • Run the tests with the right settings, ie python manage.py tests settings=[project].settings.test
    class TestJsonSchemaSerializer(TestCase):
    
        def test_custom_serializer(self):
            resp = self.client.get('/api/others/')  # Assuming the `list` endpoint exists in this viewset
            self.assertEquals(resp.status_code, 200)