I've got a project where some changes may lead to 500 status in some views.
What is the most elegant way to make unit tests that will check all the views/pages (with static routes, without vars in them, of course) for not returning 500 status?
For unit tests you can use something like:
from django import test
from django.core.urlresolvers import reverse
from page.urls import urlpatterns
class PageTest(test.TestCase):
def test_responses(self):
for url in urlpatterns:
response = self.client.get(reverse(url.name))
self.assertEqual(response.status_code, 200)
Related
I have an application running on django. But I am getting error code 404 for some urls even though these are defined.
from .views import check_secret_key # a function in views.py
from .swagger_schema import SwaggerSchemaView # a class inheriting APIView
from .kom.kom_writer import kom_status # a function
from django.conf.urls import url
urlpatterns = [
url(r'^docs/api-docs/', SwaggerSchemaView.as_view()),
url(r'^nag/secret-key/', check_secret_key),
url(r'^nag/kom-status/', kom_status),
]
API curl http://localhost:9999/internal/docs/api-docs/ works fine but curl http://localhost:9999/internal/nag/kom-status/ and nag/secret-key fir 404 errror.
Not FoundThe requested resource was not found on this server.
I am not sure what is it that I am missing.
Note: App was recently updated from DJango 1.8 to 1.11 and djangorestframework 3.2.5 to 3.5.3. Before that it was working fine.
For debugging purpose I am just returning success response right now.
from django.http import HttpResponse
def check_secret_key(request):
r = HttpResponse("I am good", content_type='text/plain', status=200)
return r
well, your definition should be something like
urlpatterns = [
url(r'.*docs/api-docs/', SwaggerSchemaView.as_view()),
url(r'.*nag/secret-key/', check_secret_key),
url(r'.*nag/kom-status/', kom_status),
]
also you need to provide /internal url definition.
I found the issue. Application is using two wsgi.py for running django apps.
Both wsgi.py files were using
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "it.settings.prod")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nt.settings.prod")
Changing it to
os.environ["DJANGO_SETTINGS_MODULE"] = "it.settings.prod"
os.environ["DJANGO_SETTINGS_MODULE"] = "nt.settings.prod"
resolved the problem.
Took reference from https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/modwsgi/
I've created a REST API accepting a POST request in Django. The request itself works great when calling from a React front end, there should be nothing wrong with the API itself.
I want to create integration test for the API.
I've written the below test, which is basically copy/paste from the Django Documentation adapted to my API:
from django.urls import reverse, path
from rest_framework import status
from rest_framework.test import APITestCase
class SendLoginEmailTest(APITestCase):
def test_post_withValidData_loginEmailIsSent(self):
url = reverse('api_private:send_login_email')
data = {'email': 'validemail#email.com', 'token': '4d4ca980-cb0c-425d-8d2c-7e38cb33f38e'}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
I run the test using the command:
python3 manage.py test
The test fails with the following exception:
django.urls.exceptions.NoReverseMatch: Reverse for 'send_login_email' not found. 'send_login_email' is not a valid view function or pattern name.
Any ideas what I'm doing wrong?
== Update ==
Content of urls.py.
from django.urls import path
from server.api_private.views import SendLoginEmail, ValidateEmail, IsEmailValidated, ProjectSave
app_name = "api_private"
urlpatterns = [
path('send_login_email/', SendLoginEmail.as_view()),
path('validate_email/', ValidateEmail.as_view()),
path('is_email_validated/', IsEmailValidated.as_view()),
path('project_save/', ProjectSave.as_view())
]
You didn't add names to your urls. reverse functions is looking for names. Add names to all URLs that you are going to use with reverse function.
urlpatterns = [
path('send_login_email/', SendLoginEmail.as_view(), name='send_logic_email'),
...,
]
My Django project has two applications in it: a web tool and a REST interface.
I run the REST interface on my database system (e.g. db.myhost.com). This interface only has URL patterns that correspond to the various REST endpoints:
app_name = "rest"
urlpatterns = [
url(r'^report/id/(?P<rid>[0-9]+)/$', views.ReportByID.as_view()),
url(r'^report/slug/(?P<slug>[a-z0-9-]+)/$', views.ReportBySlug.as_view()),
]
Part of the data that these views ultimately show need links to the other application in my project (which I host on a separate system). That application also has URL patterns:
app_name = "mytool"
urlpatterns = [
url(r'^some/cool/path/$', views.some_cool_path),
]
The REST interface only enables the REST URL patterns, since I only want to serve REST endpoints via that host:
# On my REST system
ROOT_URL = "myproject.rest_urls"
Is there a way that I can get the REST application to load the mytool URL patterns without activating them? I don't want a user to be able to browse to db.myhost.com/some/cool/path/ and get an error because that path isn't served on that host, it's served by the web tool server instead. It would be helpful, however, to be able to use reverse() to get the mytool URLs, even if they are just relative fragments (i.e. /some/cool/path ... I could always prepend the server name, which is unlikely to ever change).
I could hard-code the necessary paths, but I'd like to avoid having to do that in case they need to change in the future.
We can do it using django test utils override_settings decorator. It will use temporary settings so, it will not have any effect on the live site.
settings.py
INSTALLED_APPS = [
# .....
'mytool',
# .....
]
ROOT_URL = "myproject.rest_urls"
mytool/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('news/<slug:slug>/', views.NewsDetailView.as_view(), name='news_detail'),
]
mytool/utils.py
from django.test.utils import override_settings
from django.urls import reverse
def temp_reverse(url_conf, url_name, url_args=(), url_kwargs={}):
#override_settings(ROOT_URLCONF=url_conf)
def get_reverse(url_name, *args, **kwargs):
return reverse(url_name, args=args, kwargs=kwargs)
return get_reverse(url_name, *url_args, **url_kwargs)
accessing the reverse for unregistered urls
from mytool.urils import temp_reverse
url = temp_reverse('mytool.urls', 'news_detail', url_kwargs={'slug': 'django-awesome'})
print(url)
# output: /news/django-awesome/
Risking this question to be too generic...
What would be the advised use case types to test in a regular implementation of a REST API using the djangorestframework plugin?
I don't know that I understand your question very well,
Code without tests is broken as designed.
So each part of an application need test. you should test the functionality of each API with unit-test, and fortunately, Django rest framework has tools for this action
http://www.django-rest-framework.org/api-guide/testing/
from django.urls import include, path, reverse
from rest_framework.test import APITestCase, URLPatternsTestCase
class AccountTests(APITestCase, URLPatternsTestCase):
urlpatterns = [
path('api/', include('api.urls')),
]
def test_create_account(self):
"""
Ensure we can create a new account object.
"""
url = reverse('account-list')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
I'm using Django's LocaleMiddleware to internationalize a part of the website I'm working on.
Here is my project's urls.py:
from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = patterns('',
url(r'^api/stuff/(?P<stuff_id>)\d+/$', ApiStuff.as_view()),
)
urlpatterns += i18n_patterns('',
url(r'^stuff/', DoStuff.as_view()),
)
The problem is, when ApiStuff.as_view() returns a 404 response (other error codes behave as expected), the LocaleMiddleware operates the request to make it redirect to /en/api/stuff/<stuff_id>, even though the /api namespace is clearly not in the i18n_patterns (at the end, it generates a 404 error too, but the content of my original response is lost).
Here is the code of ApiStuff:
import django.http
from django.views.generic import View
from project.stuff.models import Stuff
class ApiStuff(View):
#staticmethod
def get(request, *args, **kwargs):
stuff_id = kwargs['stuff_id']
try:
stuff = Stuff.objects.get(pk=stuff_id)
except Stuff.DoesNotExist:
return response({"error": "stuff not found"}, 404)
result = stuff.serialize()
return response(result)
def response(data, status=200):
data = json.dumps(data)
return django.http.HttpResponse(data, status=status, content_type='application/json')
I'm using django 1.6.10 (I know, it's late, but I can't update the version right now).
Am I missing something?
This is an old bug that has been tracked here:
https://code.djangoproject.com/ticket/17734
The 404 error handler is a default handler of Django. It obviously takes the current language into account in order to translate the "not found" message.
Unless you can upgrade to a newer version you probably need to define your own error handler (including route/url).
EDIT:
As a workaround it might be possible to extend the LocaleMiddleware and maybe also CommonMiddleware. However, it could be that the 404 handler does its magic nevertheless. Might be worth a shot though because it should only require few lines of code.
Citing the ticket:
when you request /api/raising/404/, it is redirecting the user to /en/api/raising/404/ (assuming it detects the language as en). If it tests before redirecting the user if /en/api/raising/404/ is resolvable, it would find out that this would raise a 404 as well and thus would not redirect the user.
EDIT 2:
As an alternative you could simply not use i18n_patterns and just detect/switch the language via browser/cookie/parameter. I did that for a project (which included Django CMS) where I kept running into problems with these URLs. It is definitely not a prerequisite for localized Django sites to use i18n URL patterns. It's just something on top, but not at all necessary. Localization will work just fine without it. If you need help with the middleware for switching languages, drop a comment.
One can get around this issue by using following url config
urlpatterns += i18n_patterns(
url(r'^(?!api.*)stuff', DoStuff.as_view()),
)