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.
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 have defined the following custome action for my ViewSet Agenda:
class AgendaViewSet(viewsets.ModelViewSet):
"""
A simple viewset to retrieve all the Agendas
"""
queryset = Agenda.objects.all()
serializer_class = AgendaSerializer
#action(detail=False, methods=['GET'])
def get_user_agenda(self, request, pk=None):
print('here1')
id = request.GET.get("id_user")
if not id:
return Response("No id in the request.", status=400)
id = int(id)
user = User.objects.filter(pk=id)
if not user:
return Response("No existant user with the given id.", status=400)
response = self.queryset.filter(UserRef__in=user)
if not response:
return Response("No existant Agenda.", status=400)
serializer = AgendaSerializer(response, many=True)
return Response(serializer.data)
Here, I'd like to unit-test my custom action named "get_user_agenda".
However, when I'm testing, the debug output("here1") doesn't show up, and it always returns 200 as a status_code.
Here's my test:
def test_GetUserAgenda(self):
request_url = f'Agenda/get_user_agenda/'
view = AgendaViewSet.as_view(actions={'get': 'retrieve'})
request = self.factory.get(request_url, {'id_user': 15})
response = view(request)
self.assertEqual(response.status_code, 400)
Note that:
self.factory = APIRequestFactory()
Am I missing something?
Sincerely,
You will have to use the method name of the custom action and not retrieve so:
view = AgendaViewSet.as_view(actions={'get': 'get_user_agenda'})
You have to specify request url
#action(detail=False, methods=['GET'], url_path='get_user_agenda')
def get_user_agenda(self, request, pk=None):
And in my opinion it would be better to use detail=True, and get pk from url.
For example: 'Agenda/pk_here/get_user_agenda/'
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 new to Django and a small detail has been bothering me.I have an api endpoint that returns the details of one patient. I have made a successful get request and tested on postman. It returns data for a particular patient with id = 996(I have hard coded the id). But I need to set it so it can pick the id from params in postman instead of the hard coded one here. How can I set params and append them on the url so that I use the id fed in postman instead of hard coding? Kindly assist
views.py
class PatientDetailsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
try:
result = {}
auth = cc_authenticate()
res = getPatientDetails(auth["key"], id)
result = res
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
error = getattr(e, "message", repr(e))
result["errors"] = error
result["status"] = "error"
return Response(result, status=status.HTTP_400_BAD_REQUEST)
api_service.py
def getPatientDetails(auth, id):
print("getting patientdetails from Callcenter")
try:
print(auth)
# print(url)
id= 996
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/patients/v1/details/?id={id}'
print(url)
res = requests.get(url, headers=headers)
print("returning patientdetails response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path("details/", views.PatientDetailsView.as_view(), name="patient_info"),
This is the code I needed
id = request.GET.get('<id>')
Currrently I am testing my django rest api, but I am stuck on delete method.
My url looks like this
path('books/shelfs/<int:shelf>/readers/<int:pk>/',
views.ReaderViewSet.as_view(
{'get': 'retrieve', 'delete': 'destroy', 'patch': 'partial_update'}),
And My ViewSets looks like this
def destroy(self, request, pk=None, *args, **kwargs):
if request.data.get("book_type") is None:
raise ParseError(detail="book_type is required, options are : 'global, non-global'")
try:
instance = self.get_object()
user = self.request.user
serializer = self.get_serializer(self.get_object())
.......
self.perform_destroy(instance)
except Http404:
pass
return Response(status=status.HTTP_204_NO_CONTENT)
And my test case is this
def test_book_delete(self):
# check if delete works
book_type = {'book_type': 'global'}
response = self.client.delete("/api/v1/books/shelfs/{}/"
"readers/{}/".format(
1, 2), data=book_type)
self.assertEqual(response.status_code, 204)
But its alway 415 error
The question is, how to pass this book_type in delete ?
HTTP 415 means that the server refused to accept the JSON payload.
Docs:
If you need to explicitly encode the request body, you can do so by setting the content_type flag.
So try to set the content_type as follows:
response = self.client.delete("/api/v1/books/shelfs/{}/"
"readers/{}/".format(
1, 2), data=book_type, content_type="application/json")