I'm trying to write an integration test for a Django application to test if the password was changed from a rest API. However, after calling the password change API, testing for the new password doesn't work.
What I'm doing here is: I change the password to johnjohn
through a rest call, then try to check if the password is actually changed
My unittest file
import json
import urllib
import urllib2
import requests
from django.contrib.auth.models import User
from django.test import TestCase
from adaptors.redis_class import DjangoRedis
class PasswordChange(TestCase):
def setUp(self):
User.objects.create_user(username='john', email='john@john.com', password='john')
# class for redis access
r = DjangoRedis()
r.set("email:john@john.com", '0' * 40, ex=3600)
r.set('0' * 40, "email:john@john.com", ex=3600)
def test_change_password(self):
# Fake url I set through redis
url = 'http://127.0.0.1:8000/reset/' + '0' * 40 + '/'
r = requests.get(url)
csrf_token = r.content.split('csrf_token')[1].split('"')[2]
payload = {'csrfmiddlewaretoken': csrf_token, 'payload': json.dumps({'password': 'johnjohn'})}
headers = {'Cookie': 'csrftoken=' + csrf_token}
data = urllib.urlencode(payload)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
json_res = json.loads(response.read())
# This doesn't fail
self.assertEqual(json_res['password_changed'], True)
u = User.objects.get(username='john')
# This fails
self.assertEqual(u.check_password('johnjohn'),True)
My view
import hashlib
import random
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404
from django.http import JsonResponse
from django.shortcuts import render
from django.views.generic import View
from adaptors.redis_class import DjangoRedis
from constants import PASSWORD_RESET
from tasks import send_email
from util.rest import get_payload
class ResetPage(View):
def post(self, requests, reset_token):
r = DjangoRedis()
token = r.get(reset_token)
if token is None:
return JsonResponse({"token": False})
payload = get_payload(requests.POST)
try:
email = token.split(':')[1].lower()
u = User.objects.get(email=email)
u.set_password(payload['password'])
u.save()
r.delete(reset_token)
r.delete('email:' + email)
return JsonResponse({'password_changed': True})
except ValueError:
return JsonResponse({"password_changed": False, 'error': "can't get your email from the database (E01)"})
except ObjectDoesNotExist:
return JsonResponse({"password_changed": False, 'error': "User doesn't exist (E02)"})
def get(self, requests, reset_token):
r = DjangoRedis()
if not r.get(reset_token):
raise Http404
return render(requests, "login/reset.html", {'token': reset_token})
The unittest file is called rest_pass_login_tests.py
in a unittests
directory.
I run it by using the following command.
./manage.py test unittests/ --pattern="rest_pass_login_tests.py"
When I test normally through the browser, the password change works fine. However, when I try to check if the password was changed or not through a unittest, I get an invalid password.
What am I doing wrong?
You are not making an http
post
as your view expects.Here is how to make a post using urllib2: Making a POST call instead of GET using urllib2
But, since you already use
requests
module why not simply do:And maybe try debugging/printing the value of
json_res
to check if there's anything else unexpected.Also note, this is an integration test as you are testing through http, so your urls.py, views.py and even settings.py are being tested as part of it.
I was using dev server to run unittests. When I changed my password, I was actually posting to the dev server instead of the test one.
Here is my new unittest
If you're going to use
selenium
IDE, make sure you inherent fromStaticLiveServerTestCase
instead of unittest. Follow this example. Also, don't forget to change this variableself.base_url
toself.live_server_url
This inside my setUp method
self.base_url = self.live_server_url
Thanks to fips, koterpillar for helping me on the IRC channel, and aks for commenting under me.