I would like to write unit tests for my Django app that is using python-social-auth . It all works great when running Django and using a browser, thanks python-social-auth!
However, I can't seem to write unit tests because I can't create an authenticated client to test with.
Has anyone done so successfully?
How did you get an authenticated client()?
I have tried this (the login returns false and does not work):
self.c = Client()
self.u = User.objects.create(username="testuser", password="password", is_staff=True, is_active=True, is_superuser=True)
self.u.save()
self.auth = UserSocialAuth(user=self.u, provider="Facebook")
self.auth.save()
self.c.login(username=self.u.username, password=self.u.password)
Got it:
My mistake was thinking that it mattered how that Client got authenticated, for unit testing the views/endpoints oauth really doesn't need to come into play at all.
this worked for me:
self.user = User.objects.create(username='testuser', password='12345', is_active=True, is_staff=True, is_superuser=True)
self.user.set_password('hello')
self.user.save()
self.user = authenticate(username='testuser', password='hello')
login = self.c.login(username='testuser', password='hello')
self.assertTrue(login)
I have found a workaround to the issue by using the django.test.Client.force_login() method instead. With it, you need to fetch a user from the database, whose data is probably stored in a fixture , and specify the authentication backend in the second argument.
Here's the code I've used:
from random import sample
class SubscribeTestCase(TestCase):
fixtures = (
"auth.User.json", "social_django.UserSocialAuth.json",
"<myapp>.CustomProfileUser.json", "<myapp>.SubscriptionPlan.json"
)
def test_user_logged_in(self):
users = User.objects.all()
user = sample(list(users), 1)[0]
# This isn't actually used inside this method
social_user = user.social_auth.get(provider="auth0")
self.client.force_login(
user, "django.contrib.auth.backends.ModelBackend"
)
response = self.client.get(
reverse("<myappnamespace>:subscribe")
)
print(response.content)
# Looking for a way to fetch the user after a
# response was returned? Seems a little hard, see below
I am not sure how you can access a user in a Django unit test scenario after having received a Response
object, which as the documentation observes is not the same as the usual HttpResponse
used in production environments. I have done a quick research and it does look like developers aren't intended to do that. In my case I didn't need that so I didn't dig deeper.
If one checks Python Social Auth - Django source code , one will see a file in social-app-django/tests/test_views.py
that contains an example to test authenticating the user with Facebook.
from unittest import mock
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
from django.test import TestCase, override_settings
from django.urls import reverse
from social_django.models import UserSocialAuth
from social_django.views import get_session_timeout
@override_settings(SOCIAL_AUTH_FACEBOOK_KEY='1',
SOCIAL_AUTH_FACEBOOK_SECRET='2')
class TestViews(TestCase):
def setUp(self):
session = self.client.session
session['facebook_state'] = '1'
session.save()
def test_begin_view(self):
response = self.client.get(reverse('social:begin', kwargs={'backend': 'facebook'}))
self.assertEqual(response.status_code, 302)
url = reverse('social:begin', kwargs={'backend': 'blabla'})
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
@mock.patch('social_core.backends.base.BaseAuth.request')
def test_complete(self, mock_request):
url = reverse('social:complete', kwargs={'backend': 'facebook'})
url += '?code=2&state=1'
mock_request.return_value.json.return_value = {'access_token': '123'}
with mock.patch('django.contrib.sessions.backends.base.SessionBase'
'.set_expiry', side_effect=[OverflowError, None]):
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/accounts/profile/')
To use with another social backend is relatively straightforward; simply substitute facebook
with the one one is using.
Also, note that the example doesn't consider partial pipelines but the code can be adjusted to consider them too.
Note:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.