2

I'm working on my first project which uses Django REST Framework, and I'm having issues testing the API. I'm getting 403 Forbidden errors instead of the expected 200 or 201. However, the API works as expected.

I have been going through DRF Testing docs, and it all seems straightforward, but I believe my client is not being logged in. Normally in my Django projects I use a mixture of factory boy and django webtest which I've had a lot of happy success with. I'm not finding that same happiness testing the DRF API after a couple days of fiddling around.

I'm not sure if this is a problem relating to something I'm doing wrong with DRF APITestCase/APIClient or a problem with the django test in general.

I'm just pasting the following code and not posting the serializers/viewsets because the API works in the browser, it seems I'm just having issues with the APIClient authentication in the APITestCase.

# settings.py
REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}


# tests.py
from django.test import TestCase

from rest_framework.test import APITestCase, APIClient

from accounts.models import User
from .factories import StaffUserFactory


class MainSetUp(TestCase):
    def setUp(self):
        self.user = StaffUserFactory
        self.api_root = '/api/v0/'
        self.client = APIClient()


class APITests(MainSetUp, APITestCase):

    def test_create_feedback(self):
        """
        Ensure we can create a new account object.
        """
        self.client.login(username='staffuser', password='staffpassword')

        url = '%sfeedback/' % self.api_root
        data = {
            'feedback': 'this is test feedback'
        }
        response = self.client.post(url, data, user=self.user)

        self.assertEqual(response.status_code, 201)
        self.assertEqual(response.data, data)


# factories.py
from factory.django import DjangoModelFactory

from django.contrib.auth import get_user_model

User = get_user_model()


class UserFactory(DjangoModelFactory):
    class Meta:
        model = User


class StaffUserFactory(UserFactory):
    username = 'staffuser'
    password = 'staffpassword'
    email = '[email protected]'
    first_name = 'Staff'
    last_name = 'User'
    is_staff = True

3 Answers 3

1

I've never used DjangoModelFactory before, but it appears that you have to call create after setting your user to the StaffUserFactory. http://factoryboy.readthedocs.org/en/latest/_modules/factory/django.html#DjangoModelFactory

class MainSetUp(TestCase):
    def setUp(self):
        self.user = StaffUserFactory
        self.user.create()
        self.api_root = '/api/v0/'
        self.client = APIClient()
Sign up to request clarification or add additional context in comments.

Comments

1

I bet your User's password is not being set properly. You should use set_password. As a start, trying changing your setUp to this:

def setUp(self):
    self.user = StaffUserFactory
    self.user.set_password('staffpassword')
    self.user.save() # You could probably omit this, but set_password does't call it
    self.api_root = '/api/v0/'
    self.client = APIClient()

If that works, you probably want to override _generate() in your factory to add that step.

Another thing to check would be that SessionAuthentication is in your DEFAULT_AUTHENTICATION_CLASSES setting.

Comments

0

I think you must instantiate the Factory to get real object, like this:

self.user = StaffUserFactory()

Hope that help.

Moreover, you don't need to create a seperate class for staff, just set is_staff=True is enough. Like this:

self.user = UseFactory(is_staff=True)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.