Test password protected page django - django

I want to write test cases about password-protected pages.
I have /management/edit page. it is loginrequired page. My test case currently likes below, but it is failed. I am expecting to get 200 but instead of I got redirection(302)
Tests.py
from django.test import TestCase, Client
# Admin panel Test cases
class PageTest(TestCase):
# it will redirect user to loginpage
def test_admin_page(self):
response = self.client.get("/management/")
self.assertEquals(response.status_code, 302)
def test_edit(self):
c = Client()
c.login(username='admin', password='admin')
response = c.get("/management/edit/")
self.assertEquals(response.status_code,200)

I replaced login with force_login
c = self.client
testuser = User.objects.create_user(username='useresu', password='666pass')
c.force_login(testuser)

Related

Unit Test Case of redirection after successful Login of auth login view in Django

I have used django auth login view and mentioned LOGIN_REDIRECT_URL = '/team/' in my settings.py. Now i want to write the unit test case if user successfully login then it should redirect to /team/. Can anybody help me.
Thanks in advance..
My Login Url is:
path('login/', auth_views.LoginView.as_view(template_name = 'accounts/login.html'), name="login"),
My Test Case is :
class TestTeamsListView(TestCase):
def setUp(self):
obj1 = User.objects.create(username='test',email= 'abc#gmail.com', first_name='t', last_name='u', password="password")
self.login_url = reverse('accounts:login')
def test_on_successful_login(self):
client = Client()
response = client.post(self.login_url,{'username':'test','password':'password'},format='text/html')
self.assertEqual(response.status_code, 302)
When i run test then i am getting this result:
AssertionError: 200 != 302
You created a user with a password that is not hashed, as a result the login fails, and it returns the form with errors. You should create the user with .create_user(…) [Django-doc]:
obj1 = User.objects.create_user(
username='test',
email='abc#gmail.com',
first_name='t',
last_name='u',
password='password'
)

Django testing, after login still get response 302, expecting 200

I'm testing django app login part.
my work flow is client.get('/run/experiment/1') -> response 302, redirect to login page -> client.post('loginpage', {'username': 'tester', 'password': 'tester'}) -> client.get('/run/experiment/1') -> response 200.
I have tested this flow in shell (type and execute the command line by line), and it worked as expected.
But when I write the test file, even after post the login, I still got the status 302 when trying to client.get.
Here is my code:
from django.test import TestCase, Client
class TestRunRequireLogin(TestCase):
def setUp(self):
self.client = Client()
def test_rerun_not_login(self):
response = self.client.get('/experiment/1')
self.assertEqual(response.status_code, 302)
def test_rerun_login(self):
self.client.post('/accounts/login/?next=/run/experiment/1', {'username': 'tester', 'password': 'tester'})
response = self.client.get('/experiment/1')
self.assertEqual(response.status_code, 200)
So my question is when in test_rerun_login, why I still got 302 after login
Do you have users? Do you have a user with username tester and password tester? If so you need to create them in your testcase.
Might be handy to post your view up there.Can you print the form.errors? You might find the answer there.
Tests are run against an empty database. You need to create a user in the setUp method.

Only able to login ONCE with Selenium and Django Testing

I'm testing using Django's tests and Selenium so I can run tests with a live browser. But it won't let me log in more then once.
I am using Django's StaticLiveServerTestCase to access both static and media files live. I login by going to the page. I've tried putting the login code both in setUpClass to run once at the beginning and setUp to run each time. Both only let me log in once.
Here's the code:
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.contrib.auth.models import User
from selenium import webdriver
#override_settings(DEBUG=True)
class LoginTest(StaticLiveServerTestCase):
#classmethod
def setUpClass(cls):
super().setUpClass()
# create user
cls.user = User.objects.create_user( 'Testing User', 'somewhere#wherever.com', 'pwd')
# initalize webdriver
cls.driver = webdriver.Chrome() # doesn't work on FireFox either
cls.driver.set_window_size(1280,800)
cls.driver.implicitly_wait(5)
# login - send username and password to login page
cls.driver.get(cls.live_server_url+'/accounts/login/')
cls.driver.implicitly_wait(10)
username = cls.driver.find_element_by_name('login')
username.clear()
username.send_keys(cls.user.username)
password = cls.driver.find_element_by_name('password')
password.clear()
password.send_keys("pwd")
password.submit() # eubmits form
#classmethod
def tearDownClass(cls):
cls.driver.quit() # quit after tests have run
super().tearDownClass()
def test_login_one(self): # this test PASSES
self.driver.get(self.live_server_url) # go to home page
login_menu = self.driver.find_element_by_id('login_menu')
self.assertTrue(
# if logged in username is in text of #login_menu
self.user.username in login_menu.text
)
def test_login_two(self): # this test FAILS
self.driver.get(self.live_server_url) # go to home page
login_menu = self.driver.find_element_by_id('login_menu')
self.assertTrue(
# if logged in username is in text of #login_menu
self.user.username in login_menu.text
)
This code logs in once at the beginning. But I've also tried code that logs in each time a test is run (using setUp instead of 'setUpClass') and it still only lets me log in once.
Any idea what's going on?
Update:
I tried logging in a second time on test_log_in_two (the 2nd test) and I saw a "username and password not found" error in the chrome window.
What you are trying to achieve here is the capability of log in twice which is possible you just have to make a simple check inside your test method for presence of element after login happened, an if found you can simply logout and let the remaining code do it's work. Let me show you with a template what I am trying to say here :
#override_settings(DEBUG=True)
class LoginTest(StaticLiveServerTestCase):
#classmethod
def setUpClass(cls):
super().setUpClass()
logInFunction()
#classmethod
def tearDownClass(cls):
cls.driver.quit() # quit after tests have run
super().tearDownClass()
def test_login_one(self): # this test PASSES
if checkForAlreadyLoggedInElement() :
call logoutFunction()
logInFunction()
self.assertTrue(checkForAlreadyLoggedInElement())
def test_login_two(self):
if checkForAlreadyLoggedInElement() :
call logoutFunction()
logInFunction()
logoutFunction()
logInFunction()
self.assertTrue(checkForAlreadyLoggedInElement())
Hope the template clears the picture on how you should proceed. Let me know if you have any other doubts.

Django test Client simulate logged in user

I am new to Django test Client. I want to test a view that uses #login_required . I was wondering if I can do that using the simple Client() like this:
>>> from django.test import Client
>>> c = Client()
>>> r = c.get("/libros/nuevo_libro/perfil/farseer/")
But, of course, the response is always a 302:
>>> r.status_code
302
Cause the #login_required decorator redirects it to the login page.
Is it possible to simulate in this kind of tests that the user is logged in?
The test client has a login method.
c = Client()
c.login(username='fred', password='secret')
response = c.get("/libros/nuevo_libro/perfil/farseer/")

How to Create Session Variables in Selenium/Django Unit Test?

I'm trying to write a functional test that uses Selenium to test a Django view. When the user comes to a page ("page2"), the view that renders that page expects to find a session variable "uid" (user ID). I've read a half dozen articles on how this is supposed to be done but none of them have worked for me. The code below shows how the Django documentation says it should be done but it doesn't work for me either. When I run the test, the view never completes executing and I get a "server error occurred" message. Could someone please tell me what I'm doing wrong? Thank you.
views.py:
from django.shortcuts import render_to_response
def page2(request):
uid = request.session['uid']
return render_to_response('session_tests/page2.html', {'uid': uid})
test.py:
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client
class SessionTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
self.client = Client()
self.session = self.client.session
self.session['uid'] = 1
def tearDown(self):
self.browser.implicitly_wait(3)
self.browser.quit()
def test_session(self):
self.browser.get(self.live_server_url + '/session_tests/page2/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Page 2', body.text)
Here's how to solve this problem. James Aylett hinted at the solution when he mentioned the session ID above. jscn showed how to set up a session but he didn't mention the importance of the session key to a solution and he also didn't discuss how to link the session state to Selenium's browser object.
First, you have to understand that when you create a session key/value pair (e.g. 'uid'=1), Django's middleware will create a session key/data/expiration date record in your backend of choice (database, file, etc.). The response object will then send that session key in a cookie back to the client's browser. When the browser sends a subsequent request, it will send a cookie back that contains that key which is then used by the middleware to lookup the user's session items.
Thus, the solution required 1.) finding a way to obtain the session key that is generated when you create a session item and then; 2.) finding a way to pass that key back in a cookie via Selenium's Firefox webdriver browser object. Here's the code that does that:
selenium_test.py:
-----------------
from django.conf import settings
from django.test import LiveServerTestCase
from selenium import webdriver
from django.test.client import Client
import pdb
def create_session_store():
""" Creates a session storage object. """
from django.utils.importlib import import_module
engine = import_module(settings.SESSION_ENGINE)
# Implement a database session store object that will contain the session key.
store = engine.SessionStore()
store.save()
return store
class SeleniumTestCase(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
self.client = Client()
def tearDown(self):
self.browser.implicitly_wait(3)
self.browser.quit()
def test_welcome_page(self):
#pdb.set_trace()
# Create a session storage object.
session_store = create_session_store()
# In pdb, you can do 'session_store.session_key' to view the session key just created.
# Create a session object from the session store object.
session_items = session_store
# Add a session key/value pair.
session_items['uid'] = 1
session_items.save()
# Go to the correct domain.
self.browser.get(self.live_server_url)
# Add the session key to the cookie that will be sent back to the server.
self.browser.add_cookie({'name': settings.SESSION_COOKIE_NAME, 'value': session_store.session_key})
# In pdb, do 'self.browser.get_cookies() to verify that it's there.'
# The client sends a request to the view that's expecting the session item.
self.browser.get(self.live_server_url + '/signup/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Welcome', body.text)
There are a couple of tickets in Django's bug tracker around this kind of problem, the main one seems to be: https://code.djangoproject.com/ticket/10899 which hasn't had any movement on it for a few months. Basically, you need to do some extra set up to get the session to work properly. Here's what worked for me (may not work as is with your particular set up, as I wasn't using Selenium):
def setUp(self):
from django.conf import settings
engine = import_module(settings.SESSION_ENGINE)
store = engine.SessionStore()
store.save()
self.client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key
Now you should be able to access self.client.session and it should remember any changes you make to it.
Here is my solution for django==2.2.
from importlib import import_module
from django.conf import settings
from django.contrib.auth import get_user_model
# create the session database instance
engine = import_module(settings.SESSION_ENGINE)
session = engine.SessionStore()
# create the user and instantly login
User = get_user_model()
temp_user = User.objects.create(username='admin')
temp_user.set_password('password')
self.client.login(username='admin', password='password')
# get session object and insert data
session = self.client.session
session[key] = value
session.save()
# update selenium instance with sessionID
selenium.add_cookie({'name': 'sessionid', 'value': session._SessionBase__session_key,
'secure': False, 'path': '/'})