awwester
awwester

Reputation: 10172

testing Django REST Framework

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

Upvotes: 2

Views: 3136

Answers (3)

Manh Tai
Manh Tai

Reputation: 376

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)

Upvotes: 0

kevinharvey
kevinharvey

Reputation: 858

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.

Upvotes: 1

Alexander
Alexander

Reputation: 871

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

Upvotes: 1

Related Questions