Adam
Adam

Reputation: 2552

Unable to authenticate using factory-boy Django

I'm quite new to factory-boy and I'm trying to send a request to an API endpoint in my unit test, which requires a user to be authenticated. The endpoint expects a token in the header in the form of 'Bearer ' + token. I've looked at a few examples online and this is what I've come up with so far in my unit test:

test_user.py

class UserFactory(factory.Factory):
    class Meta:
        model = user

    username = factory.LazyAttribute(lambda t: "myuser")
    password = factory.PostGenerationMethodCall('set_password', 'my_super_secret')
    is_staff = True
    is_active = True

class UserViewSetTest(TestCase):
    def setUp(self):
        pwd = 'my_super_secret'
        self.user = UserFactory(password=pwd)
        self.client = Client()
        self.assertTrue(self.client.login(username=self.user.username, password=pwd))

    def test_user_list(self):
        response = self.client.get(reverse('user', kwargs={'fromdate': '2017-01-01', 'todate': '2017-04-01'})), format='json')
        self.assertEqual(response.status_code, 200)

The initial error is the fact that this assertion self.assertTrue(self.client.login(username=self.user.username, password=pwd)) is false so the test fails right away. Even if I remove that line, the API call returns a 401 because the authentication isn't successful.

How can I successfully authenticate a user in this API call with factory-boy so that I can send a token in the API request? Can I use a user model provided by the framework?

EDIT:

I've tried to create a token in order to pass it through the header as such:

def setUp(self):
    self.user = UserFactory.create()
    self.factory = APIRequestFactory()
    self.token = Token.objects.create(user=self.user)
    self.token.save()

def test_user_list(self):
    self.client = APIClient()
    self.client.credentials(HTTP-AUTHORIZATION='Bearer ' + self.token.key)
    response = self.client.get(reverse('user', kwargs={'fromdate': '2017-01-01', 'todate': '2017-04-01'})), format='json')
    self.assertEqual(response.status_code, 200)

However, I'm still getting an

AssertionError: 401 != 200

I've also seen that there is a force_authentication method but I'm not sure how to use it. Any help is appreciated.

Upvotes: 1

Views: 696

Answers (2)

Adam
Adam

Reputation: 2552

I have forced the authentication in the following way. I'm not sure this is the best practice as it seems to be bypassing the issue rather than resolving it, so if anyone else has other ideas, please let me know.

view = views.{VIEWSET_ENDPOINT}.as_view({'get': 'list'})
request = self.factory.get('{ENDPOINT}')
force_authenticate(request, user=self.user)
response = view(request)

Upvotes: 2

Tim Nyborg
Tim Nyborg

Reputation: 1649

You're using factory.Factory instead of factory.django.DjangoModelFactory.

factory.Factory doesn't automatically save to the db, so you can either switch to DjangoModelFactory, or run self.user.save() manually

You also don't need self.client = Client(), as self.client already exists

Upvotes: 5

Related Questions