I'm not finding the way to get when the PermissionDenied error is raised.
This test try to catch a Permission Denied on a Django, it is expected just to accept staff user or return a 403 status_code
This is the code:
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from django.test import Client, TestCase
from django.urls import reverse
from scrapers.models import Scraper
class PublicWebTestCase(TestCase):
def setUp(self):
# Every test needs a client.
self.client = Client()
# Create staff user (no staff)
self.user = User.objects.create_user('juan', 'juan#myemail.com.ar', 'juan')
self.staff_user = User.objects.create_user(
'victor',
'victor#lala.com.ar',
'Vitor',
is_staff=True
)
self.client.raise_request_exception = True
# crear un scraper para que haya una vista de el
self.scraper = Scraper.objects.create(
name='My Scraper',
folder="X",
)
self.page_url = reverse('scrapers-page')
def test_scrapers_page_for_anon_user(self):
""" Scrapers view as anonymous user """
self.assertRaises(PermissionDenied, self.client.get, self.page_url)
And this is the result I get:
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
Forbidden (Permission denied): /scrapers/
Traceback (most recent call last):
File "/home/lugezz/Dev/lll/env/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/lugezz/Dev/lll/env/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/lugezz/Dev/lll/env/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/home/lugezz/Dev/lll/stud/scrapers/mixins.py", line 14, in dispatch
raise PermissionDenied
django.core.exceptions.PermissionDenied
F
======================================================================
FAIL: test_scrapers_page_for_anon_user (core.tests.test_scrapers_page_privacy.PublicWebTestCase)
Scrapers view as anonymous user
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/lugezz/Dev/lll/stud/core/tests/test_scrapers_page_privacy.py", line 42, in test_scrapers_page_for_anon_user
self.assertRaises(PermissionDenied, self.client.get, self.page_url)
AssertionError: PermissionDenied not raised by get
----------------------------------------------------------------------
Ran 1 test in 0.394s
FAILED (failures=1)
What am I missing?? Thanks in advance.
Related
I am trying to run the following test:
tests.py
from rest_framework.test import APITestCase
from myapp.routing import application
from channels.testing import WebsocketCommunicator
from account.models import User
from rest_framework.authtoken.models import Token
class Tests(APITestCase):
def setUp(self):
self.user = User.objects.create(email='test#test.test',
password='a password')
self.token, created = Token.objects.get_or_create(user=self.user)
async def test_connect(self):
communicator = WebsocketCommunicator(application, f"/ws/user/{self.token}/")
connected, subprotocol = await communicator.connect()
self.assertTrue(connected)
await communicator.disconnect()
application is a boilerplate instance of channels.routing.ProtocolTypeRouter (like in here: https://channels.readthedocs.io/en/latest/topics/routing.html). Everything works fine in production. The test exits with the following error:
Traceback (most recent call last):
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/testing.py", line 74, in receive_output
return await self.output_queue.get()
File "/usr/lib/python3.7/asyncio/queues.py", line 159, in get
await getter
concurrent.futures._base.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/sync.py", line 223, in __call__
return call_result.result()
File "/usr/lib/python3.7/concurrent/futures/_base.py", line 428, in result
return self.__get_result()
File "/usr/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/sync.py", line 292, in main_wrap
result = await self.awaitable(*args, **kwargs)
File "/home/projects/myapp/myapp-api/app/tests.py", line 35, in test_connect
connected, subprotocol = await communicator.connect()
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/channels/testing/websocket.py", line 36, in connect
response = await self.receive_output(timeout)
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/testing.py", line 85, in receive_output
raise e
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/testing.py", line 74, in receive_output
return await self.output_queue.get()
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/timeout.py", line 66, in __aexit__
self._do_exit(exc_type)
File "/home/projects/myapp/myapp-env/lib/python3.7/site-packages/asgiref/timeout.py", line 103, in _do_exit
raise asyncio.TimeoutError
concurrent.futures._base.TimeoutError
----------------------------------------------------------------------
Ran 1 test in 1.026s
I have tried python versions 3.7.5, 3.8.0 and 3.9.9 using channels 3.0.4 with django 3.2.10 and channels-redis 3.3.1 ('BACKEND': 'channels_redis.core.RedisChannelLayer' in settings.py). The error persists. What am I doing wrong?
I had the same problem. APITestCase or TestCase dont allow transactions, you have to use SimpleTestCase from django test, and set databases to all. Just with that difference i think it will work.
Note that the transactions will be saved between test, and not rolled back after the test.
from django.test import SimpleTestCase
from myapp.routing import application
from channels.testing import WebsocketCommunicator
from account.models import User
from rest_framework.authtoken.models import Token
class Tests(SimpleTestCase):
databases = '__all__'
def setUp(self):
self.user = User.objects.create(email='test#test.test', password='a password')
self.token, created = Token.objects.get_or_create(user=self.user)
async def test_connect(self):
communicator = WebsocketCommunicator(application, f"/ws/user/{self.token}/")
connected, subprotocol = await communicator.connect()
self.assertTrue(connected)
await communicator.disconnect()
here are the information of SimpleTestCase
https://docs.djangoproject.com/en/4.0/topics/testing/tools/
I faced a similar issue and the solution is usually to mimic your production router for the tests too, i.e whatever middleware or additional component used in production should also be added when imstantiating your Communicator. for example in my asgi.py I have:
application = ProtocolTypeRouter(
{
"http": get_asgi_application(),
"websocket": AllowedHostsOriginValidator(
jwt_auth_middleware_stack(URLRouter(chat.routing.websocket_urlpatterns)),
),
}
)
My communicator is instantiated as follows:
communicator = WebsocketCommunicator(jwt_auth_middleware_stack(URLRouter(websocket_urlpatterns)),
f"/ws/chat/{chat.id}/?token={token}")
And my url is:
websocket_urlpatterns = [
path("ws/chat/<str:chat_id>/", consumers.AsyncChatConsumer.as_asgi())
]
I use Django and Graphene in my project. I wrote tests with GraphQLTestCase. When i try to authenticate users using JWT, i usually get errors.
Here is my code:
from django.test import TestCase
import json
from graphene_django.utils.testing import GraphQLTestCase
from resume.graph.schema import schema
from .models import Post
from django.contrib.auth import get_user_model
from graphql_jwt.shortcuts import get_token
User = get_user_model()
class PostTestCase(GraphQLTestCase):
GRAPHQL_SCHEMA = schema
def test_post_list(self):
token = get_token(User.objects.get(pk=1))
headers = {"HTTP_AUTHORIZATION": f"JWT {token}"}
response = self.query(
'''
query {
post{
user
text
}
}
''',
op_name = 'post',
headers=headers,
)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
Here are the errors I get after running python manage.py test.
Traceback (most recent call last):
File "C:\Users\Udemezue\Desktop\resume\post\tests.py", line 25, in test_post_list
token = get_token(User.objects.get(pk=9))
File "C:\Users\Udemezue\Desktop\resume\env\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Udemezue\Desktop\resume\env\lib\site-packages\django\db\models\query.py", line 415, in get
raise self.model.DoesNotExist(
accounts.models.User.DoesNotExist: User matching query does not exist.
Here is the errors i get.
======================================================================
FAIL: test_post_list (post.tests.PostTestCase)
Traceback (most recent call last):
File "C:\Users\Udemezue\Desktop\resume\post\tests.py", line 62, in test_post_list
self.assertResponseNoErrors(response)
File "C:\Users\Udemezue\Desktop\resume\env\lib\site-packages\graphene_django\utils\testing.py", line 75, in assertResponseNoErrors
self.assertEqual(resp.status_code, 200)
AssertionError: 400 != 200
Ran 1 test in 0.137s
FAILED (failures=1)
Destroying test database for alias 'default'...
This works for me.
from django.contrib.auth import get_user_model
from graphql_jwt.shortcuts import get_token
User = get_user_model()
import json
class PostTestCase(GraphQLTestCase):
def test_post_list(self):
user = get_user_model().objects.create(username='myuser')
token = get_token(user)
headers = {"HTTP_AUTHORIZATION": f"JWT {token}"}
response = self.query(
'''
query GetUser($username: String!) {
user(username: $username) {
id
}
}
''',
headers=headers,
)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
I am new to web.py . I was following ex52 LPTHW , and I had to perform nosetests on all the tests in tests folder. But I am getting 1 failed test due to assertion error. I tried reading different assertion errors and why they occur , but I cant figure out this one. I tried expanding the errors which the server could possibly show up like 500 Internal , 400 but its still failing the test. I have created the other code just like mentioned in the book: http://learnpythonthehardway.org/book/ex52.html
Here is my traceback:
C:\lpthw\gothonweb>cd tests
C:\lpthw\gothonweb\tests>nosetests
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\web\application.py", line 239, in process
return self.handle()
File "C:\Python27\lib\site-packages\web\application.py", line 230, in handle
return self._delegate(fn, self.fvars, args)
File "C:\Python27\lib\site-packages\web\application.py", line 420, in _delegate
return handle_class(cls)
File "C:\Python27\lib\site-packages\web\application.py", line 396, in handle_class
return tocall(*args)
File "C:\lpthw\gothonweb\bin\app.py", line 29, in GET
return render.hello_form()
File "C:\Python27\lib\site-packages\web\template.py", line 1017, in __getattr__
t = self._template(name)
File "C:\Python27\lib\site-packages\web\template.py", line 1014, in _template
return self._load_template(name)
File "C:\Python27\lib\site-packages\web\template.py", line 1001, in _load_template
raise AttributeError, "No template named " + name
AttributeError: No template named hello_form
F...
======================================================================
FAIL: tests.app_tests.test_index
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\nose\case.py", line 197, in runTest
self.test(*self.arg)
File "C:\lpthw\gothonweb\tests\app_tests.py", line 12, in test_index
assert_response(resp)
File "C:\lpthw\gothonweb\tests\tools.py", line 5, in assert_response
assert status in resp.status, "Expected response %r not in %r" % (status , resp.status)
AssertionError: Expected response '200' not in '500 Internal Server Error'
----------------------------------------------------------------------
Ran 4 tests in 0.562s
FAILED (failures=1)
My tests code: app_tests.py
from nose.tools import *
from bin.app import app
from tests.tools import assert_response
def test_index():
#check that we get a 404 on the / URL
resp = app.request("/")
assert_response(resp, status= "404")
#test our first GET request to /hello
resp = app.request("/hello")
assert_response(resp)
#make sure default values work for the form
resp = app.request("/hello" , method="POST")
assert_response(resp , contains="Nobody")
#test that we get expected values
data = {'name':'Tejas','greet':'Ola!'}
resp = app.request("/hello " , method= "POST", data=data)
assert_response(resp , contains="Zed")
tools.py :
from nose.tools import *
import re
def assert_response(resp, contains=None, matches=None, headers=None, status= "200"):
assert status in resp.status, "Expected response %r not in %r" % (status , resp.status)
if status == "200":
assert resp.data , "Response data is empty."
if contains:
assert contains in resp.data, "Response does not contain %r" % contains
if matches:
reg = re.compile(matches)
assert reg.matches(resp.data), "Response does not match %r" % matches
if headers:
assert_equal(resp.headers , headers)
app.py code:
import web
from gothonweb import map
urls = (
'/game' , 'GameEngine' ,
'/' , 'Index',
)
app = web.application(urls, globals())
#little hack so that debug mode works with sessions
if web.config.get('_session') is None:
store= web.session.DiskStore('sessions')
session= web.session.Session(app, store, initializer={'room':None})
web.config._session = session
else:
session= web.config._session
render = web.template.render('templates/', base="layout")
class Index(object):
def GET(self):
#this is used to "setup" the session with starting values
session.room= map.START
web.seeother("/game")
class GameEngine(object):
def GET(self):
if session.room:
return render.show_room(room= session.room)
else:
#why is there here? do you need it?
return render.you_died()
def POST(self):
form= web.input(action=None)
if session.room and form.action:
session.room= session.room.go(form.action)
else:
session.room= None
if __name__ == "__main__" :
app.run()
After going ahead with the exercise now it gives me 2 import errors:
PS C:\lpthw\gothonweb\tests> nosetests
EE
======================================================================
ERROR: Failure: SyntaxError (invalid syntax (app.py, line 2))
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\nose\loader.py", line 418, in loadTestsFromName
addr.filename, addr.module)
File "C:\Python27\lib\site-packages\nose\importer.py", line 47, in importFromPath
return self.importFromDir(dir_path, fqname)
File "C:\Python27\lib\site-packages\nose\importer.py", line 94, in importFromDir
mod = load_module(part_fqname, fh, filename, desc)
File "C:\lpthw\gothonweb\tests\app_tests.py", line 2, in <module>
from bin.app import app
File "C:\lpthw\gothonweb\bin\app.py", line 2
from gothonweb import map.py
^
SyntaxError: invalid syntax
======================================================================
ERROR: Failure: ImportError (cannot import name map)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\nose\loader.py", line 418, in loadTestsFromName
addr.filename, addr.module)
File "C:\Python27\lib\site-packages\nose\importer.py", line 47, in importFromPath
return self.importFromDir(dir_path, fqname)
File "C:\Python27\lib\site-packages\nose\importer.py", line 94, in importFromDir
mod = load_module(part_fqname, fh, filename, desc)
File "C:\lpthw\gothonweb\tests\map_tests.py", line 2, in <module>
from gothonweb import map
ImportError: cannot import name map
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (errors=2)
directory structure:
C:/lpthw/
gothonweb/
bin build dist doc sessions Gothonweb templates tests map.py app.py
tests/
map_tests.py
app_tests.py
__init__.py
tools.py
What should I do to fix the error? Thanks for the suggestions.
For this error,
"AttributeError: No template named hello_form"
use an absolute path and see if that works, instead of
"render = web.template.render('templates/', base="layout")
try:
"render = web.template.render('C:/lpthw/gothonweb/bin/templates', base="layout")
Amazingly, your test has nothing to do with app.py.
from nose.tools import *
from bin.app import app
from tests.tools import assert_response
def test_index():
#check that we get a 404 on the / URL
resp = app.request("/")
assert_response(resp, status= "404")
#test our first GET request to /hello
resp = app.request("/hello")
assert_response(resp)
#make sure default values work for the form
resp = app.request("/hello" , method="POST")
assert_response(resp , contains="Nobody")
#test that we get expected values
data = {'name':'Tejas','greet':'Ola!'}
resp = app.request("/hello " , method= "POST", data=data)
assert_response(resp , contains="Zed")
App.py
import web
from gothonweb import map
urls = (
'/game' , 'GameEngine' ,
'/' , 'Index',
)
app = web.application(urls, globals())
#little hack so that debug mode works with sessions
if web.config.get('_session') is None:
store= web.session.DiskStore('sessions')
session= web.session.Session(app, store, initializer={'room':None})
web.config._session = session
else:
session= web.config._session
render = web.template.render('templates/', base="layout")
class Index(object):
def GET(self):
#this is used to "setup" the session with starting values
session.room= map.START
web.seeother("/game")
class GameEngine(object):
def GET(self):
if session.room:
return render.show_room(room= session.room)
else:
#why is there here? do you need it?
return render.you_died()
def POST(self):
form= web.input(action=None)
if session.room and form.action:
session.room= session.room.go(form.action)
else:
session.room= None
if __name__ == "__main__" :
app.run()
Can you see, how they are not related
Your first test says you should get a 404 on the '/' url but that would only happen if '/' didn't exist. Your app.py code clearly shows that '/' calls on GET in the Index class.
Second test, resp = app.request("/hello") now that would give you a 404 error because that url doesn't exist on app.py
The same goes for the third test as '/hello' doesn't exist in your tuple of urls in app.py
And the fifth test as well
Although your tests are invalid, the primary problem you have though is trying to perform the automated test from inside the tests directory; that's wrong.
C:\lpthw\gothonweb\tests> nosetests
This is not the right thing to do, you need to be a directory below for all your imports to work e.g In app_tests you are trying to import bin/app.py but that's not in the 'tests' directory
Do this instead
C:\lpthw\gothonweb> nosetests
This way all the files that you need would be imported
Back to app_tests.py. I'll write out a very simple test that's actually related to app.py
from bin.app import app
from test.tools import assert_response
def test_index():
#check that we get a 303 on the / url
#this is because web.seeother() will always send the browser this http code
resp = app.request("/")
assert_response(resp, status= "303")
def test_game():
#check that we get a 200 on /game
resp = app.request("/game")
assert_response(resp, status = '200')
#check that we have response data on a form sumbit
resp = app.request("/game", method = 'POST')
aseert_response(resp.data)
The assertion_error you getting because your ran nosetests in this directory
/gothroweb/test
you should run it in
/gothroweb
bin docs gothonweb templates tests
./bin:
app.py app.pyc __init__.py __init__.pyc
./docs:
./gothonweb:
__init__.py __init__.pyc
./templates:
hello_form.html index.html layout.html
./tests:
app_tests.py __init__.py test.html tools.pyc
app_tests.pyc __init__.pyc tools.py
cheers
I'm using Django==1.9.2 and djangorestframework==3.3.2, and django.test.Client to make some tests. The problem is that when I execute my tests I'm gettting this error:
ERROR: test_view (main.tests.test_http.TestMainViewSet)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/vladir/work/all/project-django1.9/saxo-publish/publish/main/tests/test_http.py", line 111, in test_view
content_type='application/json'
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/test/client.py", line 515, in post
secure=secure, **extra)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/test/client.py", line 314, in post
secure=secure, **extra)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/test/client.py", line 380, in generic
return self.request(**r)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/test/client.py", line 449, in request
response = self.handler(environ)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/test/client.py", line 123, in __call__
response = self.get_response(request)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 245, in get_response
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 296, in handle_uncaught_exception
return callback(request, **param_dict)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 166, in _wrapped_view
return middleware.process_response(request, response)
File "/home/vladir/work/all/project-django1.9/venv/local/lib/python2.7/site-packages/django/middleware/csrf.py", line 230, in process_response
request.META["CSRF_COOKIE"],
KeyError: u'CSRF_COOKIE'
My test code looks like this:
import json
from django.test import Client
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
class TestMainViewSet(TestCase):
def setUp(self):
self.client = Client(
HTTP_HOST='example.com' # I have also tried removing this
)
self.create_read_url = reverse('books-list')
User.objects.create_user(
username="username",
email="username#zunzun.se",
password="123"
)
def test_create(self):
self.client.login(username='username', password="123")
# In this case I'm doing a POST, but it is the same with a GET
response = self.client.post(
self.create_read_url,
data=json.dumps({'title': "Create"}), # I have also tried without the json.dumps
content_type='application/json'
)
data = json.loads(response.content)
print data
self.assertEqual(response.status_code, 201)
self.assertEquals(data['title'], "Create")
my view code is:
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework import viewsets
from .serialiazers import (
BookSerializerRead,
BookSerializerWrite,
)
class MainViewSet(LoginRequiredMixin, viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class_read = BookSerializerRead
serializer_class_write = BookSerializerWrite
on the urls.py:
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'books', MainViewSet, 'books')
urlpatterns = [
url(r'^api/', include(router.urls)),
]
According with the Django doc about it, I should not need anything additional to avoid the CSRF checks,
because as textually said there: "By default, the test client will disable any CSRF checks performed by your site.", and I also know that enforce_csrf_checks=False by default
on the Client.
I have found one detail though, if I create an instance of the client that way self.client = Client(HTTP_HOST='example.com', CSRF_COOKIE='xxxxxx') then it works, but is that
actually needed? It is not what the documentation says, so I suppose I'm doing something wrong. Could someone help me with that please? I will appreciate any help about.
Thanks in advance
Try to use DRF's APITestCase as base class for test cases:
from rest_framework.testing import APITestCase
class TestMainViewSet(APITestCase):
...
In views.py:
get_dict = Site.objects.getDictionary(request.COOKIES['siteid'])
{gets a dictionary with site information based on id from cookie}
In tests.py:
from django.test import TestCase
class WebAppTest(TestCase):
def test_status(self):
response = self.client.get('/main/',{})
response.status_code # --->passed with code 200
response = self.client.get('/webpage/',{'blog':1})
response.status_code # ----> this is failing
In order to present blog page it goes to a view where it gets a dictionary using existing cookie, process it, renders templates, which works fine when running the app. But the tests are failing.Having never tested Django webapps I'm not sure how to test it right. Here is the traceback.
Traceback (most recent call last):
File "<console>", line 2, in <module>
File "/usr/lib/pymodules/python2.6/django/test/client.py", line 313, in post
response = self.request(**r)
File "/usr/lib/pymodules/python2.6/django/core/handlers/base.py", line 92, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/var/lib/django/data/../webpage/views.py", line 237, in getCostInfo
get_dict = Site.objects.getDictionary(request.COOKIES['siteid'])
KeyError: 'siteid'
Went through some online samples but couldn't find something that deals in depth with cookies/sessions. Any ideas or directs to useful links are highly appreciated.
Take a look at the Persistent State section of the Django Testing docs.
In your case, I would expect your test to be something more like:
from django.test import TestCase
from django.test.client import Client
class WebAppTest(TestCase):
def setUp(self):
self.client = Client()
session = self.client.session
session['siteid'] = 69 ## Or any valid siteid.
session.save()
def test_status(self):
response = self.client.get('/main/',{})
self.assertEqual(response.status_code, 200)
response = self.client.get('/webpage/',{'blog':1})
self.assertEqual(response.status_code, 200)