Search code examples
djangounit-testingdjango-rest-frameworkdjango-unittestfactory-boy

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.


Solution

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