Reverse does not work for the test.py

Hi!
I’m trying to create tests for my project. I don’t understand why my function doesn’t work “reverse”. Even though it seems like I’m doing everything right. The project also uses two languages and a database with extensions btree_gin and pg_trgm

urls.py

urlpatterns = [
    path("books/", views.Books, name="books"),
]

test.py

class CustomUserTests(TestCase):
    def test_check(self):    # it doen't work
        url = reverse("books")
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)

# but it works. 
# Of course, I can use this method, but it is not convenient, 
# it seems to me, for further use, as I have large url
def test_check_second(self): 
        response = self.client.get("/books/")
        self.assertEquals(response.status_code, 200)

This is how I load extensions btree_gin and pg_trgm into the database. This may not be the best way, I realise, but it didn’t work through the migration file.

signals.py

def app_pre_migration(sender, app_config, **kwargs):

    cur = connection.cursor()
    cur.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;")
    cur.execute("CREATE EXTENSION IF NOT EXISTS btree_gin;")


pre_migrate.connect(app_pre_migration, sender=apps.get_app_config("books"))

What is your root urls.py looks like?

Leandro de Souza, hello! Thank you for your your response. Yes, I forgot about root urls.py. I attach it bellow.

root urls.py

urlpatterns = [
       path("", include("books.urls")),
]

urlpatterns += i18n_patterns(
     path("", include("books.urls")),
)

Do you have an app_name defined in books? If so, that creates a namespace that needs to be used as the prefix for the urls. (See URL namespaces)

If not, please post the complete urls.py along with the complete traceback of the error message you are receiving.

Ken, hello! Thank you for response.
I don’t use a namespace. I attach urls.py and traceback of the error message below.

traceback

Found 7 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F......
======================================================================
FAIL: test_check (books.tests.CustomUserTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/user/Desktop/project/books/tests.py", line 19, in test_check
    self.assertEquals(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 7 tests in 1.884s

FAILED (failures=1)
Destroying test database for alias 'default'...

root urls.py

from django.urls import include, path

urlpatterns = [
     path("", include("books.urls")),
]
urlpatterns += i18n_patterns(
    path("", include("books.urls")),
)

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

books/urls.py

from django.urls import include, path
from . import views

urlpatterns = [
    path("books/", views.Books, name="books"),
]

Sorry, I missed this the first time:

Keep in mind that reversing a url by name is going to return the last defined url with that name, and so reversing ‘books’ may return something like “/en/books/”. (Actually, I would suggest trying this in the shell to actually see what it reverses as. Or, at a minimum, print the url in the test to see what it’s trying to request.)

Ken, you’re right. If I comment out (disable) i18n_patterns and use only urlpatterns, everything works. Why is this the case? And how can I fix it because I want to test in two languages?
By the way, as you wrote, I did it in the shell, and it seems to me that reverse returns the default language in the settings because I tried switching them. But maybe I’m wrong.

urlpatterns = [
     path("", include("books.urls")),
]
If I do this, it works
#urlpatterns += i18n_patterns(
#    path("", include("books.urls")),
#)

Add a print to the test to see what reverse is returning in that. I’m guessing it may be something “odd”.

You may also want to review the docs at Translation | Django documentation | Django to see if there’s useful information available.

1 Like

Ken, you are also right here :slight_smile:

from django.utils.translation import activate

class CustomUserTests(TestCase):
    def test_check(self): 
        activate("en") # if I use it, it works
        url = reverse("books")
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)

I found this in the link in the docs you sent me. Thank you!
Ken, why is this the case? Do I need to write it every time because HTTP_ACCEPT_LANGUAGE='en' doesn’t work.

Pure conjecture - in the test suite you’re not actually issuing an http request. The test framework is building the request directly and calling the view, bypassing all the wsgi-layer “stuff”.

1 Like

Ken, thank you! I understand.
I may found other solution.

class CustomUserTests(TestCase):
    def test_check(self): 
        with translation.override("en"):
                url = reverse("books")
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)

If you don’t want to do this with each test, could you use activate in your setUp method?

1 Like

Ken, I tried it and it works. You right :slight_smile: Thank you!

 class CustomUserTests(TestCase):
    def setUp(self):
         activate("en")

    def test_check(self): 
        url = reverse("books")
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)