Getting errors running automated test for register APIView

Hello everyone, I’m seeing errors when I run automated tests for my Register APIView API endpoint. I’m building a test with DRF and I think I set up everything correctly, I’m following the DRF docs.

Here is my automated test (test_register.py)

class UserRegisterTests(APITestCase):
    def test_register_user(self):
        
        url = reverse('arborfindr:register')
        data = {'email': 'myemail@mail.com', 'password': 'mypassword123'}
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(User.objects.count(), 2)
        self.assertEqual(User.objects.post().email, 'myemail@mail.com')
        self.assertTrue(User.objects.check_password('mypassword123'))

register serializers

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

views.py

# API endpoint for registration
@authentication_classes([JWTAuthentication])
class RegisterView(APIView):
  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)

Finally here is the error traceback

Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: 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
    self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 400 != 201

----------------------------------------------------------------------
Ran 1 test in 0.015s

Here is the link to the example I followed for testing with DRF Testing - Django REST framework.

Please I need help with this, in the docs the Response is set to status.HTTP_201_CREATED but not sure if I should change the status code.

Please let me know if you need anything else from me.

Side note: The Django Rest Framework is a third-party library with its own support channels.
While there are people here who do try to help with DRF-related issues, it’s possible that you might get faster results if you ask your question in one of those areas.

1 Like

Thank you. I appreciate, I’ll ask there

Perhaps I’m just an impatient person. But I the response time isn’t that fast on the DRF support forum, if I can even call it that.

I still haven’t heard anything from anyone, and there are some posts/messages I’ve seen that are weeks/months old. I mean you responded faster. I guess I can keep waiting, I’m not familiar with this new forum, it’s set up as an email inbox

The username field is present in the serializer definition and is probably required as per the User model, but you don’t provide a value for it in data sent.

When receiving the 400 response, if you printed the response content, it would tell you that this field is missing

So how do I add username and where? I’m sorry, little confused. I’m just trying to understand what you’re saying

Do you mean provider a value, just like I did with email/password keys in UserRegisterTests in my test_register.py?

This is where you define the data sent to to your view in your test. So, you should add a username to this dict.

That’s what’s this testing error? Something so simple, don’t know how I overlooked this. I’ll try this and get back to you. Fingers crossed it works

So like this then ```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.assertEqual(response.status_code, status.HTTP_201_CREATED)
    self.assertEqual(User.objects.count(), 2)
    self.assertEqual(User.objects.post().email, 'myemail@mail.com')
    self.assertTrue(User.objects.check_password('mypassword123'))```

So I made the changes and now I get this error ```System check identified no issues (0 silenced).
E

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 15, in test_register_user
self.assertEqual(User.objects.post().email, ‘myemail@mail.com’)
^^^^^^^^^^^^^^^^^
AttributeError: ‘UserManager’ object has no attribute ‘post’


Ran 1 test in 0.244s

FAILED (errors=1)
Destroying test database for alias ‘default’…```. It’s referring to my POST request, should it be GET instead?

Error message is clear enough. On this line in your test

You use User.objects.post() where post is not a known method of the manager. What would you expect such call to do ?

The following line User.objects.check_password will also likely fail.

I don’t know why you have 2 users in your database after running the test (as per the previous User.objects.count() test). May be your test suite is creating another user in test setup… Anyway… you want to test the created user has the correct email and password: this should be done on an User instance, not on the manager. So your test would probably be something like:

self.assertTrue(User.objects.filter(username='jonedoe12').exists())
user = User.objects.get(username='jonedoe12')
self.assertEqual(user.email, 'myemail@email.com')
self.assertTrue(user.check_password('mypassword123'))

Yeah, I followed the example under ‘API Test Cases’ in Testing - Django REST framework.

Also I was getting some help with my testing from another Django developer in the Discord Django channel. He said to use POST instead, since before I was using GET as per the DRF docs testing. Anyway here is my modified tests ```class UserRegisterTests(APITestCase):
def test_register_user(self):

    url = reverse('arborfindr:register')
    data = {'email': 'myemail@mail.com', 'username': 'jonedoe12', 'password': 'mypassword123'}
    response = self.client.get(url, data, format='json')
    self.assertTrue(User.objects.filter(username='jonedoe12').exists())
    user = User.objects.get(username='jonedoe12')
    self.assertEqual(user.email, 'myemail@email.com')
    self.assertTrue(user.check_password('mypassword123'))```

I never told you to change the client.post with client.get. The former is the correct form.

So just change it back to POST like I had it before and that’s it? That’s the only thing?

It worked, thank you so much. Still a little unclear on what you meant regarding two users in the db though.

This test

It was ok in your test, so that means you have two users in your database after the test runs. You’re creating one (jonedoe12) in this unit test. I just wonder where does the second one come from !

Ah I see what you mean. Yeah I didn’t need it then I guess

So I’m trying to do the same thing, i.e. create an automated test with the login apiview, but I’m not exactly sure on how to implement DRF properly in it. I was following the ‘Authenticating’ example in ‘APIClient’ in DRF docs. I know the setup looks similar to the register test, but it should be different I think. Anyway here is the code for my login test ```from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from …models import User
from rest_framework.test import APIClient

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'))

class UserLoginTests(APITestCase):
def test_login_user(self):
url = reverse(‘arborfindr:login’)
data = {‘email’: ‘newmail@mail.com’, ‘username’: ‘janedoe87’, ‘password’: ‘newpassword123’}
response = self.client.post(url, data, format=‘json’)
client = APIClient()
client.login(usernmae=‘janedoe87’, password=‘newpassword123’)```