im new to django and im working on a webesite and i want to write unit tests for it and im kind of confused how to do it.
does it make any sense to get urls from django its self and test their views?
from django.test import TestCase
from django.urls import get_resolver
from kernel.settings.base import TEMPLATES_DIR
class ViewTest(TestCase):
Site_urls= list(set(v[1] for k,v in get_resolver().reverse_dict.items()))
Site_urls= [i.replace('\\','') for i in Site_urls]
Site_urls= [i.replace('/','') for i in Site_urls]
Site_urls= [i.replace('$','') for i in Site_urls]
def urlexists(self):
for i in self.Site_urls:
with self.subTest(line= i):
response = self.client.get(f'/{i}/')
self.assertEqual(response.status_code, 200)
my url examples:
urlpatterns = [
path('about/', aboutView.as_view(),name='About'),
]
also other tests like if view uses correct template which acquires url names...
so is this the correct way of doing it or should i use static files?
Yes, if you want to check if the url correspond to the right view.
here is a example
url correspond to the right view
from .views import register_view
from django.urls.base import resolve
class RegisterTests(TestCase):
def test_register_view(self):
view = resolve('/account/register')
self.assertEqual(
view.func.__name__,
register_view.__name__,
)
When you run python manage.py test, it should passed if you set the right view.
url correspond to the right template
use reverse and client.get to visit your url.
from django.urls.base import resolve, reverse # <--- new
from .views import register_view
class RegisterTests(TestCase):
def test_register_view(self):
...
def test_register_template(self): # <--- new
url = reverse('account:register')
self.response = self.client.get(url)
self.assertEqual(self.response.status_code, 200)
self.assertTemplateUsed(self.response, 'account/register.html')
Related
I am in need of some help understanding how Python and Django work based on some code I'm looking at.
Say my urls.py file has the following
router.register(r'testing', SomeClass)
and then in my views.py file, it is set up like this:
class SomeClass():
database = DatabaseValues.objects.all()
def first_def(self):
# do some filtering and such on db results
return database
def second_def(self):
a = 20
b = 40
return b - a
def third_def(self):
z = 200
y = 400
return y - z
When the SomeClass is called in UI by hitting the http://localhost/testing url, what is returned??
I would recommend making some changes to urls.py I think this method below is easier to understand.
when you run python3 manage.py runserver
you can open 127.0.0.1/example.
the reason you are not understanding is because Django has a lot of boilerplate code. I would recommend reading more into how views work.
every class in views.py should inherit a django class in this example I use TemplateView. your app name is the folder that is created when a new django "app" is added to the project.
from django.urls import path
from .views import exampleView
app_name = "example"
urlpatterns = [
path('/example', exampleView.as_view(), name='example'),
]
in views.py you cannot create arbitrary function names. when a website loads
www.baseurl/example you are making a get request. therefore you must have a get method inside of your class.
template_name refers to an html page that will be rendered...
this template name must point at an html file which is located inside project_root/templates/html_file.html
views.py
from django.views.generic import TemplateView, ListView
class exampleView(TemplateView):
template_name = 'test.html'
def get(self, request):
print("hello")
return render(request, self.template_name, {})
if you wish to have arbitrary functions inside your class cool. Add them below the get function and call them when a user makes a get request.
Here is my code looks like :-
url.py file :-
from rest_framework import routers
from view_user import user_signup,user_login
router = routers.DefaultRouter()
urlpatterns = [
url(r'^api/v1/user_signup',csrf_exempt(user_signup)),
url(r'^api/v1/user_login',csrf_exempt(user_login))
]
view_user.py file:-
def user_signup(request):
try:
if request.method == 'POST':
json_data = json.loads(request.body)
return JsonResponse(result, safe=False)
except Exception as e:
logger.error("at method user : %s", e)
So, when I call the url:- http://myserver/api/v1/user_signup
it goes to "user_signup" method of view_user.py file.
But what I want is I should be able validate my request before it goes to the user_signup method.
I want this validation for all the requests that comes to my server for all methods (ex:- user_signup,user_login ...) before it goes to respective methods.
Annotate the concerned views with a decorator that contains the logic you want to execute before the views are called.
See Python - Decorators for a head start.
And How to write a custom decorator in django?
If you want to do this on all requests, regardless of the associated view, then you should consider writing a middleware. See how to setup custom middleware in django
I am trying to create a restful api using class based views in django.
class SomeAPI(MultiDetailView):
def get(self,request,format=None):
#some logic
def post(self,request,format=None):
#some logic
I want to process a get request like www.pathtowebsite.com/api?var1=<someval>&var2=<someval>&var3=<someval>
My post url would be www.pathtowebsite.com/api/unique_token=<token_id>
Basically a get request would generate a unique token based on some parameters and a post request would post using that token.
How would my URL file look like in such a scenario?
P.S I have hardly ever worked with class based views.
First of all: DRF will do a lot of your legwork for you, even generate consistent URLs across your API. If you want to learn how to do things like this in the Django URL dispatcher then you can embed regexes in your URLS:
project/urls.py:
from django.conf.urls import url
from project.app.views import SprocketView
urlpatterns = [
url(r'^api/obj_name/(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
url(r'^api/obj_name/unique_token=(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
]
project/app/views.py
from django.shortcuts import get_object_or_404
from django.views.generic import View
from .forms import SprocketForm
from .models import Sprocket
class SprocketView(View):
def get(request, id):
object = get_object_or_404(Sprocket, pk=id)
return render(request, "sprocket.html", {'object':object}
def post(request, id):
object = Sprocket.get_or_create(pk=id)
object = SprocketForm(request.POST, initial=object).save(commit=False)
object.user = request.user
object.save()
return render(request, "sprocket.html", {'object':object, 'saved':True})
That's a lof of functionality that frameworks are supposed to lift from you and I suggest reading about Django CBV. One resource I can wholeheartedly recommend is Two Scoops.
I just started learning unittests and stuck with this problem.
I got project structure like this (it’s Django 1.6.2 now):
./manage.py
./myproject
./myproject/urls.py
./myproject/myapp/
./myproject/myapp/urls.py
./myproject/myapp/views.py
./tests/
./test/test_example.py
In the ./myproject/urls.py I have:
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^myapp/', include('myproject.myapp.urls')),
)
In the ./myproject/myapp/urls.py I have:
from django.conf.urls import patterns, url
urlpatterns = patterns('myproject.myapp.views',
url(r'^example1/$', 'itemlist'),
url(r'^example1/(?P<item_id>\w+)/$', 'item'),
)
I wrote basic test and put it into ./test/test_example.py
import unittest
from django.test import Client
class PagesTestCase(unittest.TestCase):
def setUp(self):
self.client = Client()
def test_itemlist(self):
response = self.client.get('/myapp/example1/')
self.assertEqual(response.status_code, 200)
def test_item(self):
response = self.client.get('/myapp/example1/100100/')
self.assertEqual(response.status_code, 200)
I run this tests from shell like this:
cd ./tests
python manage.py test
First test runs OK, but he second always fails with ‘404 not found’ status code.
Both urls are working OK in the browser.
Also, I tried this:
cd ./
python manage.py shell
>>> from django.test.client import Client
>>> c = Client()
>>> r = c.get('/myapp/example1/100100/')
>>> r.status_code
200
I just can’t figure out how to run those tests properly. It seems no pattern that is passed into views as parameter ever works for me. But all fixed urls are found correctly by django.test.client.
Thank you!
EDIT: I just found that 404 fires in my myproject/myapp/views.py
There is a code:
def item(request, item_id):
try:
item = Item.objects.get(pk = int(item_id))
except (ValueError, Item.DoesNotExist):
raise Http404
And here goes the Item.DoesNotExist exception. I have no any idea, why that item not found?
Use the reverse() function instead to build URLs, that is:
In ./myproject/myapp/urls.py file give each URL pattern a name parameter that is for example:
from django.conf.urls import patterns, url
urlpatterns = patterns('myproject.myapp.views',
url(r'^example1/$', 'itemlist', name='example-one'),
url(r'^example1/(?P<item_id>\w+)/$', 'item', name='example-two'),
)
We will use the value given to the name parameter to build URLs.
Then in ./test/test_example.py:
from django.core.urlresolvers import reverse
class PagesTestCase(unittest.TestCase):
...
def test_itemlist(self):
url = reverse('example-one')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_item(self):
url = reverse('example-two')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
That should do the trick.
In addition to using reverse, you can get a 404 if the expected model isn't available in the test database (as mentioned in one of the comments). You should also use Django's TestCase instead of python's unittest since the former inherits from the latter, but makes interacting with the database much easier (among other things).
An example that sets up test data:
from django.test import TestCase
from django.urls import reverse
# Or whatever your object is.
from .models import Item
class ItemViewsTestCase(TestCase):
"""Tests for Item views."""
#classmethod
def setUpTestData(cls):
"""Set up test data available for all tests in this class."""
cls.item = Item.objects.create(name='Testing')
def test_item_list_view(self):
# Note, self.client we get for free from Django's TestCase.
response = self.client.get(reverse('itemlist'))
self.assertEqual(response.status_code, 200)
def test_item_detail_view(self):
# This url pattern expects an Item.id so use the item we set up.
url = reverse('item', args=[self.item.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
I have a routing rule in my Django app for downloads that redirect to a external CDN. I am now writing tests for my app, and I want to test that the route does successfully redirect to the configured url in my Django settings. Here is a simplified example that should help explain what I'm trying to do:
from django.test import SimpleTestCase
from django.test.client import Client
from django.conf import settings
class MyTestCase(SimpleTestCase):
def setUp(self):
self.client = Client()
def test_download(self):
response = self.client.get('/download/mac/')
self.assertRedirects(response, settings.URLS.get('mac'))
Now this doesn't work, the redirect gets a 404 even though when I print settings.DOWNLOAD_URL in this method it is correct, and a copy/paste into the browser proves it works. I started to look into why it wasn't working, and I noticed this in the Django source code:
Note that assertRedirects won't work for external links since it uses
TestClient to do a request.
So then, how does one test these redirects? I'm not looking for anything super fancy, what I expect to check is the response's status_code and location. I saw that response has a follow parameter, and tried something like this, but it still didn't work:
def test_download(self):
response = self.client.get('/download/mac/', follow=True)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], settings.URLS.get('mac')
It was requested that I include the relevant parts from my urls.py and views.py, here they are:
# urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^download/(?P<platform>\w+)/$', 'download_app', name='download'),
)
#views.py
from django.conf import settings
from django.shortcuts import redirect
from django.http import Http404
def download_app(request, platform):
if platform in settings.URLS:
return redirect( settings.URLS.get(platform) )
else:
raise Http404
Any help in solving this would be much appreciated. Thanks in advance.
Probably the original poster has solved his problems and moved on long ago, but the solution here is to not specify follow=True as he did in the alternative proposal that didn't work either.
The following will simply check that the view being tested redirects as expected, without relying on the external resources.
def test_download(self):
response = self.client.get('/download/mac')
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], 'http://external/resource')
In Django 1.7 assertRedirect got a new parameter fetch_redirect_response which can be set to False to get the same effect, but I haven't tried it myself.