'How to test authenticated POST request with Pytest in Django
I want to test an authenticated post request on an API using Pytest. This is what I am doing so far:
def test_auth_user_can_create(self, client):
url = api_reverse('crud-simulation_api')
data = {
"project": "testproject",
....
}
response = client.post(url, json=data)
assert response.status_code == 200
This doesn't work because it gives me back a 401 (Unauthorized) instead of a 200. That makes sense since the fixture is a client and not an admin client.
Yet if I pass in admin_client instead of client it gives me a Bad Request. The data that I send should be fine though.
I also tried to pass in the headers like so (since I use JWT authorization):
token = "bigassstringwhichismytoken"
headers = {
"Authorization": "JWT " + token
}
Finally I tried to log in before which gives me a 403 (Forbidden):
def test_auth_user_can_create_simulation_api(self, client, django_user_model):
username = "Jack"
password = "password"
django_user_model.objects.create_user(username=username, password=password)
client.login(username=username, password=password)
url = api_reverse('crud-simulation_api')
data = {
"project": "testproject",
...
}
response = client.post(url, json=data)
assert response.status_code == 200
If someone could point me into the right direction that would be fantastic! Thanks a lot in advance
Solution 1:[1]
You can hit the login url with username and password and get the token.
creade a header dictionary like headers = {'Authorization': 'JWT <token>'}
and use the header when using post.
client.post(url, json=data, headers=headers)
Solution 2:[2]
To provide headers for client.{request}
pass them individually as keyword agruments:
client.post(url, data, HTTP_FIRST_HEADER='...', HTTP_SECOND_HEADER='...')
Although you're unlikely to collide with any reserved parameter names in post
call chain, better collect all headers you need in a dictionary:
headers = {
'HTTP_FIRST_HEADER': '...',
'HTTP_SECOND_HEADER': '...',
}
And pass them to request as arbitrary number of keyword arguments:
client.post(url, data, **headers)
In this case **
arguments are treated as extra information and are automatically added as headers.
Solution 3:[3]
I would suggest installing the pytest-django package. Based on its docs, the easiest answer would be just using the admin_client fixture. As admin_client has the type of django.test.Client, it can be used for both get and post requests.
def test_sth_with_auth(admin_client):
response = admin_client.get('/private')
assert response.status_code == 200
Also if you want to use a specific user, you can try sth like this:
@pytest.fixture
def my_user(django_user_model):
return django_user_model.objects.create_user(username=username, password=password)
@pytest.fixture
def logged_in_client(client, my_user):
return client.force_login(my_user)
def test_sth_with_auth(logged_in_client):
response = logged_in_client.get('/private')
assert response.status_code == 200
this part of the doc can be helpful to write your desired logged_in_client().
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sam |
Solution 2 | |
Solution 3 |