我使用DRF和JWT包进行身份验证。现在,我正在尝试编写一个用JWT令牌验证自身的单元测试。无论我如何尝试,我都无法让测试API客户端通过JWT进行身份验证。如果我对API客户机(在我的例子中是Postman)做同样的操作,那么一切都会正常工作。
这是测试用例:
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework_jwt.settings import api_settings
from backend.factories import member_factory
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class MemberTests(APITestCase):
def test_get_member(self):
member = member_factory()
payload = jwt_payload_handler(member.user)
token = jwt_encode_handler(payload)
self.client.credentials(Authorization='JWT {0}'.format(token))
response = self.client.get(reverse('member-detail', kwargs={'pk': member.pk}))
assert response.status_code == 200
但我总是能得到一个401 Authentication credentials were not provided
。
在response.request
中,我看到了令牌的存在,我猜它只是没有应用。
如果我重写测试以使用rest_framework.test.RequestsClient
并将其实际发送到服务器 URL,它就能工作。
在这方面有什么帮助吗?
P.S.:我知道force_authenticate()
和登录,但我希望我的单元测试能够像生产中的API客户端一样访问API。
发布于 2017-11-30 11:46:59
尝试为此测试设置一个新的APIClient。这就是我自己测试的样子
def test_api_jwt(self):
url = reverse('api-jwt-auth')
u = user_model.objects.create_user(username='user', email='user@foo.com', password='pass')
u.is_active = False
u.save()
resp = self.client.post(url, {'email':'user@foo.com', 'password':'pass'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
u.is_active = True
u.save()
resp = self.client.post(url, {'username':'user@foo.com', 'password':'pass'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertTrue('token' in resp.data)
token = resp.data['token']
#print(token)
verification_url = reverse('api-jwt-verify')
resp = self.client.post(verification_url, {'token': token}, format='json')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
resp = self.client.post(verification_url, {'token': 'abc'}, format='json')
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='JWT ' + 'abc')
resp = client.get('/api/v1/account/', data={'format': 'json'})
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
client.credentials(HTTP_AUTHORIZATION='JWT ' + token)
resp = client.get('/api/v1/account/', data={'format': 'json'})
self.assertEqual(resp.status_code, status.HTTP_200_OK)
发布于 2020-07-07 20:55:04
如果您使用的是简单JWT和吡喃,以及Python3.6+,那么下面的答案就适用了。您需要创建一个夹具,我称之为api_client
,您需要为现有用户获取令牌。
from django.contrib.auth.models import User
from rest_framework.test import APIClient
from rest_framework_simplejwt.tokens import RefreshToken
import pytest
@pytest.fixture
def api_client():
user = User.objects.create_user(username='john', email='js@js.com', password='js.sj')
client = APIClient()
refresh = RefreshToken.for_user(user)
client.credentials(HTTP_AUTHORIZATION=f'Bearer {refresh.access_token}')
return client
注意,在上面的夹具中,用户是在那里创建的,但是您可以使用另一个夹具来创建用户并将其传递给这个用户。关键元素是以下一行:
refresh = RefreshToken.for_user(user)
这一行允许您像解释的在医生里那样手动创建令牌。一旦您有了这个令牌,您就可以使用credentials
方法来设置标题,然后测试客户端将在所有后续请求中包含这些标头。注意,refresh.access_token
包含访问令牌。
在您的测试中必须使用此夹具,您需要对用户进行身份验证,如下例所示:
@pytest.mark.django_db
def test_name_of_your_test(api_client):
# Add your logic here
url = reverse('your-url')
response = api_client.get(url)
data = response.data
assert response.status_code == HTTP_200_OK
# your asserts
发布于 2019-02-01 17:56:16
我也有类似的问题,随函附上我的解决方案,只是为了比较更多的代码(tests.py)。
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from django.contrib.auth.models import User
class AuthViewsTests(APITestCase):
def setUp(self):
self.username = 'usuario'
self.password = 'contrasegna'
self.data = {
'username': self.username,
'password': self.password
}
def test_current_user(self):
# URL using path name
url = reverse('tokenAuth')
# Create a user is a workaround in order to authentication works
user = User.objects.create_user(username='usuario', email='usuario@mail.com', password='contrasegna')
self.assertEqual(user.is_active, 1, 'Active User')
# First post to get token
response = self.client.post(url, self.data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK, response.content)
token = response.data['token']
# Next post/get's will require the token to connect
self.client.credentials(HTTP_AUTHORIZATION='JWT {0}'.format(token))
response = self.client.get(reverse('currentUser'), data={'format': 'json'})
self.assertEqual(response.status_code, status.HTTP_200_OK, response.content)
https://stackoverflow.com/questions/47576635
复制