I’m creating as well as running an automated test for Profile Page API endpoint using the DRF extension APITestCase
.
I already created/ran two separate automated tests for the login/registration API endpoints with no errors in the console. I was trying to set up the test for this API similar to the other two tests.
But when I run python manage.py test
again for the HomeownerProfileAPITest in test_profile.py, I get the following error
I’m not sure if I did something wrong in my views, tests. But here are some important files that might make this clearer:
serializers.py
from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User, HomeownerUser
from .search_indexes import ArboristCompanyIndex, ServiceTypeIndex
from drf_haystack.serializers import HaystackSerializer
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password']
extra_kwargs = {
'password': {'write_only': True}
}
def validate(self, valid):
if valid['password'] != valid['password']:
raise serializers.ValidationError({"password": "Passwords do not match."})
return valid
def create(self, validated_data):
user = User.objects.create_user(
email=validated_data['email'],
username=validated_data['username'],
password=validated_data['password']
)
return user
class LoginSerializers(serializers.ModelSerializer):
email = serializers.CharField(max_length=255)
password = serializers.CharField(
label =("Password"),
style={'input_type': 'password'},
trim_whitespace=False,
max_length=128,
write_only=True
)
def validate(self, data):
email = data.get('email')
password = data.get('password')
if email and password:
user = authenticate(request=self.context.get('request'),
email=email, password=password)
if not user:
msg = ('Invalid email/password')
raise serializers.ValidationError(msg, code = 'Authorization')
else:
msg = ('Must include valid "email" and "password".')
raise serializers.ValidationError(msg, code = 'Authorization')
data['user'] = user
return data
class HomeownerProfileSerializer(serializers.ModelSerializer):
class Meta:
model = HomeownerUser
fields = ['profile_pic', 'street_address', 'homeowner_city', 'homeowner_state', 'homeowner_zip_code']
class ServiceTypeSerializer(HaystackSerializer):
class Meta:
index_class = [ServiceTypeIndex]
fields = ['text', 'name']
class CompanySerializer(HaystackSerializer):
class Meta:
index_class = [ArboristCompanyIndex]
fields = [
'text', 'company_name', 'company_city', 'company_state'
]
views
@authentication_classes([JWTAuthentication])
class LoginView(APIView):
authentication_classes = (JWTAuthentication)
def post(self, request, *args, **kwargs):
serializer = LoginSerializers(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(None, user)
token = Token.objects.create(user=user)
return Response({"status": status.HTTP_200_OK, "Token": token.key})
if user is not None:
# Generate token
refresh = RefreshToken.for_user(user)
access_token = str(refresh.access_token)
return Response({
'message': 'Successful login',
'access_token': access_token,
'refresh_token': str(refresh),
}, status=status.HTTP_200_OK)
return Response({'error': 'Invalid email/password'}, status=status.HTTP_401_UNAUTHORIZED)
@authentication_classes([JWTAuthentication])
class RegisterView(APIView):
authentication_classes = (JWTAuthentication)
def post(self, request):
serializer = RegisterSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response({
'message': 'successfully registered',
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@authentication_classes([JWTAuthentication])
class HomeownerProfileView(APIView):
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
authentication_classes = (JWTAuthentication)
serializer_class = HomeownerProfileSerializer
def get(self):
username = self.kwargs['username']
obj = get_object_or_404(User, username=username)
return obj
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
urls (app)
from django.urls import path
from arborfindr.views import index
from .views import services_info
from . import views
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static
from .views import RegisterView, LoginView, HomeownerProfileView
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from rest_framework import routers
app_name = 'arborfindr'
#router = routers.DefaultRouter
#router.register('company/search', CompanySearchView, base_name='company-search')
urlpatterns = [
path('register/', RegisterView.as_view(), name='register'), # Register API endpoint url
path('login/', LoginView.as_view(), name ='login'), # Login API endpoint url
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('update_password/', views.update_password, name='update_password'),
path('api/users/<user_id>/profile/', HomeownerProfileView.as_view()),
path('services/', services_info),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('arborfindr/', index),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And finally test_profile.py
from rest_framework.test import APITestCase
from ..models import User
from django.test import TestCase, Client
class HomeownerProfileTest(APITestCase):
def setUp(self):
self.user = User.objects.create_user(username='test_homeowner', password='password321')
def test_profile(self):
client = APIClient()
client.login(username='test_homeowner', password='password321')
response = client.get(f'api/users/{self.user.id}/profile')
self.assertEqual(response.status_code, status.HTTP_200_OK)
error traceback
show_sunset_warning()
System check identified no issues (0 silenced).
.FE
======================================================================
ERROR: test_register_user (arborfindr.test.test_register.UserRegisterTests.test_register_user)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/coreyj/Documents/ArborHub/MyProject/arborfindr/test/test_register.py", line 12, in test_register_user
response = self.client.post(url, data, format='json')
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/test.py", line 295, in post
response = super().post(
path, data=data, format=format, content_type=content_type, **extra)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/test.py", line 209, in post
return self.generic('POST', path, data, content_type, **extra)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/test.py", line 233, in generic
return super().generic(
~~~~~~~~~~~~~~~^
method, path, data, content_type, secure, **extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/test/client.py", line 676, in generic
return self.request(**r)
~~~~~~~~~~~~^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/test.py", line 285, in request
return super().request(**kwargs)
~~~~~~~~~~~~~~~^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/test.py", line 237, in request
request = super().request(**kwargs)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/test/client.py", line 1092, in request
self.check_exception(response)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/test/client.py", line 805, in check_exception
raise exc_value
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper
return view_func(request, *args, **kwargs)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 497, in dispatch
self.initial(request, *args, **kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 415, in initial
self.check_permissions(request)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 331, in check_permissions
for permission in self.get_permissions():
~~~~~~~~~~~~~~~~~~~~^^
File "/home/coreyj/Documents/ArborHub/MyProject/.venv/lib64/python3.13/site-packages/rest_framework/views.py", line 278, in get_permissions
return [permission() for permission in self.permission_classes]
^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'BasePermissionMetaclass' object is not iterable
======================================================================
FAIL: test_profile (arborfindr.test.test_profile.HomeownerProfileTest.test_profile)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/coreyj/Documents/ArborHub/MyProject/arborfindr/test/test_profile.py", line 18, in test_profile
self.assertEqual(response.status_code, 200)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 404 != 200
----------------------------------------------------------------------
Ran 3 tests in 0.936s
FAILED (failures=1, errors=1)
Destroying test database for alias 'default'...
test_register_user
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from ..models import User
# Unit test for user registration API endpoint
class UserRegisterTests(APITestCase):
def test_register_user(self):
url = reverse('arborfindr:register')
data = {'email': 'myemail@mail.com', 'username': 'jonedoe12', 'password': 'mypassword123'}
response = self.client.post(url, data, format='json')
self.assertTrue(User.objects.filter(username='jonedoe12').exists())
user = User.objects.get(username='jonedoe12')
self.assertEqual(user.email, 'myemail@mail.com')
self.assertTrue(user.check_password('mypassword123'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
As you can see, it's throwing a status error message. I added the code for the 200 status like I did with the other tests
You don't have to pass "user_id" into HomeownerProfileTest.test_profile, Just set it up in "setUp", "setUpTestData", or inside "test_profile"
class HomeownerProfileTest(APITestCase):
def setUp(self):
# you can set user_id here for multiple testcase if needed
self.user = User.objects.create_user(username='test_homeowner', password='password321')
def test_profile(self):
client = Client()
client.login(username='test_homeowner', password='password321')
response = client.get(f'api/users/{self.user.id}/profile/')
self.assertEqual(response.status_code, 200)