I have a basic Asynchronous Class Based View:
class AsyncAuthenticationView(View):
async def post(self, request, *args, **kwargs):
authenticated: bool = await sync_to_async(lambda: request.user.is_authenticated)()
if not authenticated:
return HttpResponse('Unauthorized', status=401)
return HttpResponse('Success', status=200)
And two simple tests:
#pytest.fixture
def authenticated_async_client(user) -> AsyncClient:
client = AsyncClient()
client.force_login(user)
return client
class TestAsyncAuthenticationView:
#pytest.mark.asyncio
async def test_with_async_client(self, authenticated_async_client: AsyncClient):
"""This test fails, with response code 401 instead of 200"""
response = await authenticated_async_client.post(
reverse('auth-test'),
'abc',
content_type="text/html",
)
assert 200 == response.status_code # fails with 401
#pytest.mark.asyncio
async def test_with_async_request_factory(self, async_rf: AsyncRequestFactory, user):
"""This test succeeds correctly with response code 200"""
r = async_rf.post('/fake-url', 'abc', content_type='text/html')
r.user = user
r.session = {}
response = await AsyncAuthenticationView().post(r)
assert 200 == response.status_code
The first test which uses the AsyncClient always fails to authenticate returning status code 401 while the second test is passing just fine with status code 200.
Based on the docs the AsyncClient has all the same methods, so I am not not why the test is failing. Perhaps there is a different authentication method that needs to be used?
The AsyncRequestFactory that is being used in the second test is from the pytest-django package.
Any help would be much appreciated. Thank you.
Related
I have a post method under View Set. I need to write a unit test case for the method. when I pass param its give None. How should I pass both param and data(payload).
views.py
#action(detail=True, methods=['post'])
def complete_task(self, request, *args, **kwargs):
"""
Method for complete the task
input post request : task_id : str, variable_return:boolean, request data: dict
output Response : gives whether task is completed or not
"""
try:
get_task_id = self.request.query_params.get("task_id")
get_process_variables = request.data
print(get_task_id)
print(get_process_variables)
complete_task = CamundaWriteMixins.complete_task(url=CAMUNDA_URL, task_id=get_task_id,
process_variable_data=get_process_variables)
print("compl", complete_task)
return Response({"task_status": str(complete_task)})
except Exception as error:
return Response(error)
test.py
def test_completed_task(self):
self.client = Client()
url = reverse('complete-task')
data = {"variables": {
"dept_status": {"value": "approved", "type": "String"}}
}
response = self.client.post(url, data=data, params={"task_id": "000c29840512"},
headers={'Content-Type': 'application/json'})
print(response.data)
self.assertTrue(response.data)
I have tried above test case method which is getting request data but I got param None.
Thanks in Advance,.
if you just modify your request a bit and add query param as part of your url then i guess you are good to go.
Example:
response = self.client.post(f'{url}?task_id=000c29840512', data=data,
headers={'Content-Type': 'application/json'})
you can refer the official documentation for the example: https://docs.djangoproject.com/en/4.0/topics/testing/tools/
I'm currently struggling to make this current unit-test pass:
def test_markNotifications(self):
request_url = f'Notifications/mark_notifications/'
view = NotificationsViewSet.as_view(actions={'post': 'mark_notifications'})
request = self.factory.post(request_url)
request.POST = {'id_notifs': "1"}
force_authenticate(request, user=self.user)
response = view(request)
self.assertEqual(response.status_code, 200)
Here's the associated view:
#action(detail=False, methods=['POST'])
def mark_notifications(self, request, pk=None):
"""
Put Notifications as already read.
"""
id_notifs = request.POST.get("id_notifs")
if not id_notifs:
return Response("Missing parameters.", status=400)
id_notifs = str(id_notifs).split(",")
print(id_notifs)
for id in id_notifs:
notif = Notification.objects.filter(pk=id).first()
if not notif:
return Response("No existant notification with the given id.", status=400)
notif.isRead = True
notif.save()
return Response("Notifications have been marked as read.", status=200)
The problem is that even though I'm passing "id_notifs" through the request in test, I'm getting None when I do id_notifs = request.POST.get("id_notifs").
It seems that the id_notifs I'm passing in the POST request are neither in the body and the form-data. In this context, I have no idea on how to access them.
Looking forward some help, thanks.
I have added a method to my viewset as follows:
class CustomImageViewSet(viewsets.ModelViewSet):
queryset = CustomImage.objects.all()
serializer_class = CustomImageSerializer
lookup_field = 'id'
#action(detail=True, methods=['get'], url_path='sepia/')
def sepia(self, request, id):
# do something
data = image_to_string(image)
return HttpResponse(data, content_type="image/png", status=status.HTTP_200_OK)
Since it is not a default or overridden request method, I am not sure how can I proceed writing a test for it. Any suggestions?
You're not clear on what the test should test but you can test the response status_code for example like this:
def test_sepia_api():
api_client = APIClient()
response = api_client.get(path="{path_to_your_api}/sepia/")
assert response.status_code == 200
I noticed you were using pytest. I'll assume you've got pytest-django too then (it really does make everything easier). I like using request factory since it's generally faster if you've got authentication needs.
def test_me(self, user, rf):
view = CustomImageViewSet()
request = rf.get("")
request.user = user # If you need authentication
view.request = request
response = view.sepia(request, 123)
assert response.data == BLAH
I am trying to test my flask app but I am getting this error
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.`
I have tried understanding the error but all I kknow is that there is a client instance that should be instantiated to be used in testing. Help.
My code:
import unittest
from flask import jsonify
class TestAuth(unittest.TestCase):
"""Class for testing all the API endpoints"""
def setUp(self):
"""Initializing a test client and making the environment a testing one"""
app.app.config['TESTING'] = True
self.app = app.app.test_client()
self.app.testing = True
def sign_in(self, email='user#gmail.com', password='testpass'):
user_data = jsonify({"email": email, "password": password})
return self.app.post('/api/v1/auth/signup/', data=user_data)
def log_in(self, email='user#gmail.com', password='testpass'):
user_data = jsonify({"email": email, "password": password})
return self.app.post('/api/v1/auth/login/', data=user_data)
def test_home_status_code(self):
result = self.app.get('/api/v1/')
self.assertEqual(result.status_code, 200)
def test_signin_status_code(self):
result = self.sign_in()
self.assertEqual(result.status_code, 200)
def test_login_correct_login(self):
"""test login after signing in"""
self.sign_in()
result = self.log_in()
self.assertEqual(result.status_code, 200)
self.assertIn(b'Success', result.message)
def test_login_with_wrong_credentials(self):
"""test successful login"""
self.sign_in() # must sign in first for successful login
result = self.log_in(email='wrong#mail', password='wrongpass')
self.assertIn(b'Wrong Username or Password', result.message)
if __name__ == "__main__":
unittest.main()
try this:
def test_home_status_code(self):
with self.app as client:
result = client.get('/api/v1/')
self.assertEqual(result.status_code, 200)
I have a weird error writing a APITestCase for a Django REST view.
This is my code:
class CreateUserTest(APITestCase):
def setup(self):
self.superuser = User.objects.create_superuser('vishnu#vishnu.com', '1989-10-06', 'vishnupassword')
self.client.login(username='vishnu', password='vishnupassword')
self.data = a bunch of trivial data
def test_can_create_user(self):
print "create user"
self.setup()
self.token = Token.objects.get(user_id=self.superuser.id)
self.api_key = settings.API_KEY
self.factory = APIRequestFactory()
self.request = self.factory.post('/api/v1/uaaaaaasers/?api_key=%s' % self.api_key,
self.data,
HTTP_AUTHORIZATION='Token {}'.format(self.token))
force_authenticate(self.request, user=self.superuser)
self.view = UserList.as_view()
self.response = self.view(self.request)
self.response.render()
#print self.response.content
self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)
As you see I run a factory.post to an intentionally wrong url /api/v1/uaaaaaasers/
But the test doesnt complain:
Creating test database for alias 'default'...
create user .
----------------------------------------------------------------------
Ran 1 test in 0.199s
OK Destroying test database for alias 'default'...
Shouldnt it crash with that wrong url? How do I know the test is going fine?
You are testing it all wrong...
The response that you have tested is from the direct view call...
self.view = UserList.as_view()
self.response = self.view(self.request)
self.response.render()
#print self.response.content
self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)
your above case will always call the view...
In actual testcases we hit the urls with the client and test that response
self.response = self.client.post('/api/v1/uaaaaaasers/?api_key=%s' % self.api_key,
self.data,
HTTP_AUTHORIZATION='Token {}'.format(self.token))
self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)
If you want to test posting a request to an invalid url, use the test client instead of the request factory.
class CreateUserTest(APITestCase):
def test_can_create_user(self):
...
response = self.client.post(
'/api/v1/uaaaaaasers/?api_key=%s' % self.api_key,
self.data,
...
)
...