I'm using factory_boy to generate arbitrary data to run tests. but after each test it doesn't delete files automatically. Is there anything I should add?
Any suggestion is highly appreciated
Model for test
class TrackFactory(factory.django.DjangoModelFactory):
class Meta:
model = "tracks.Track"
id = factory.Faker("uuid4")
filename = "Track 01 - track"
created_by = factory.SubFactory(UserFactory)
file = factory.django.FileField(filename="test.mp3")
track_length = 145
#classmethod
def _create(cls, model_class, *args, **kwargs):
instance = cls.build(*args, **kwargs)
instance.save()
return instance
Test
class TestViewDeleteTrack(AuthorizedApiTestCase):
def setUp(self):
self.url = reverse(list-track)
self.user_data = UserFactory()
self.data = TrackFactory(created_by=self.user_data)
self.client.force_authenticate(user=self.user_data)
def test_list_tracks(self):
self.get_and_assert_equal_status_code(status.HTTP_200_OK)
def test_delete_track_valid_pk(self):
self.delete_and_assert_equal_status_code(
"delete-track",
self.data.pk,
status.HTTP_204_NO_CONTENT,
)
custom methods for testing used above
def get_and_assert_equal_status_code(self, status_code):
response = self.client.get(self.url)
self.assertEqual(response.status_code, status_code)
return response
def delete_and_assert_equal_status_code(self, url_name, pk, status_code):
url = reverse(url_name, kwargs={"pk": pk})
response = self.client.delete(url)
self.assertEqual(response.status_code, status_code)
Files arent deleted, just the database field that points to the file, you can remove them in your teardown method.
import shutil
class MyTest(AuthorizedApiTestCase):
...
def tearDown(self):
# modify to actually delete what you want to delete.
shutil.rmtree(settings.UPLOAD_FOLDER)
there is also a tearDownClass which is the reverse of the setUpClass
Related
I want to create a service using Django Rest API. I have a function. The result of this function should return 2 values and I should return these values in JSON API format.
The function will work like this. I will receive the features_list as a parameter and I will use it to create a result and display it as a service in json format in def prediction function.
I created a sample API (I guess) it is class PredictionSet in my views but I actually want to make service the def prediction function in my views.
I cannot understand how to apply it. I am so confused. Any help would be appreciated.
models.py
class Liquidity(models.Model):
pred_y = models.CharField(max_length=600)
score = models.FloatField()
views.py
class PredictionSet(viewsets.ModelViewSet):
queryset = Liquidity.objects.all()
serializer_class = LiquiditySerializer
def prediction(request, features_list):
filename = config.FINAL_MODEL_PATH
classifier = pickle.load(open(filename, 'rb'))
scale_file = config.SCALER_PATH
scaler = pickle.load(open(scale_file, 'rb'))
sample = np.array(features_list).reshape(1, -1)
sample_scaled = scaler.transform(sample)
pred_y = classifier.predict(sample_scaled)
prob_y = classifier.predict_proba(sample_scaled)
if prob_y[0][1] < 0.5:
score = 0
elif prob_y[0][1] <= 0.69:
score = 1
else:
score = 2
pred_y = pred_y[0]
prediction_obj = Liquidity.objects.get_or_create(pred_y=pred_y, score=score)
prediction_result = prediction_obj.pred_y
prediction_score = prediction_obj.score
context = {
'prediction_result ': prediction_result,
'prediction_score ': prediction_score,
}
return context
serializer.py
class LiquiditySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Liquidity
fields = '__all__'
If you want to return custom JSON from a ModelViewset in DRF, you can override .list() and/or .retrieve() like this :
from rest_framework import status
from rest_framework.response import Response
class PredictionSet(viewsets.ModelViewSet):
queryset = Liquidity.objects.all()
serializer_class = LiquiditySerializer
# Your custom function definition
def prediction(self, request, features_list):
# The content
def retrieve(self, request, *args, **kwargs):
result = prediction(...) # Call your custom service and got result
# Return the result as JSON (url = /api/v1/predictions/1) an object
return Response({'data': result}, status=status.HTTP_200_OK)
def list(self, request, *args, **kwargs):
result = prediction(...) # Call your custom service and got result
# Return the result as JSON (url = /api/v1/predictions) a list of objects
return Response({'data': result}, status=status.HTTP_200_OK)
For more details follow this link
I want to test that my view redirects after I send it correct data. The problem is that I'm using a form that needs parameters while initializing. I have a method that builds me a response that I later use in the tests. The method works for my other views but I can't make it work with views that use Forms that need parameters to initialize them.
In my forms.py I have:
class SupportIssueForm(forms.ModelForm):
class Meta:
model = SupportIssue
fields = ('user', 'property', 'title', 'text', 'is_urgent', 'is_service')
def __init__(self, person_company, properties, is_property, *args, **kwargs):
super(SupportIssueForm, self).__init__(*args, **kwargs)
self.fields['is_service'].widget.attrs['class'] = 'custom-control-input'
...
My method for generating the response I'm later using in my test looks like this:
def generate_logged_in_user_post_response(self, data):
request = self.factory.post(self.url, data={**self.form_class_args[0], **data})
request.user = self.logged_in_user
return new_support_issue_view(request)
I also tried this:
def generate_logged_in_user_post_response(self, data):
form = SupportIssueForm(**self.form_class_args[0], data=data)
request = self.factory.post(self.url, form)
request.user = self.logged_in_user
return new_support_issue_view(request)
the self.form_class_args[0] is some dictionary I declare elsewhere:
{
"person_company": person_company, # <query object>
"properties": properties, # <query object>
'is_property': False
}
I have a view set like this
class NeProjectsViewSet(viewsets.ViewSet):
def list(self, request,org_unique_id):
''' something '''
def create(self, request,org_unique_id):
''' something '''
def retrieve(self):
''' something '''
def update(self, request, pk):
''' something '''
def partial_update(self, request):
''' something '''
def destroy(self, request):
''' something '''
and i've a method like this
def check_session(self,request):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
raise ValueError('Session Expired')
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
to validate session for every request, for that i need to call this method before every method in the viewset. I read somewhere writing custom decorator is better way, so how to implement custom decorator for my view set to check session for request
Assuming you are using DRF.
I think you are going in wrong direction. If this is part of your permission layer you should just add custom permission class to your viewset
http://www.django-rest-framework.org/api-guide/permissions/
from rest_framework import permissions
class ValidateSession(permissions.BasePermission):
"""
Validate session expiration
"""
def has_permission(self, request, view):
current_datetime = datetime.now()
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return False
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
And then add it like this
class NeProjectsViewSet(viewsets.ViewSet):
permission_classes = (ValidateSession,)
...
Assuming you're using plain django
from django.contrib.auth.mixins import AccessMixin
class ValidateSessionMixin(AccessMixin):
"""
Validate session
"""
def has_permission(self):
current_datetime = datetime.now()
request = self.request
if ('last_login' in request.session):
last = (current_datetime - datetime.strptime(request.session['last_login'], "%Y-%m-%d %H:%M:%S.%f")).seconds
if last > base.SESSION_IDLE_TIMEOUT:
del request.session['token']
return True
else:
request.session['last_login'] = str(current_datetime)
return (request.session['token'] == request.META['HTTP_AUTHORIZATION'])
def dispatch(self, request, *args, **kwargs):
if not self.has_permission():
return self.handle_no_permission()
return super(ValidateSessionMixin, self).dispatch(request, *args, **kwargs)
And apply this mixin like this
class NeProjectsViewSet(ValidateSessionMixin, viewsets.ViewSet):
...
I'm using Django with DRF and python mock. What I am trying to do is to test my views and mock a serializer and some methods.
This is what I have:
views.py
from gmm_mobile.v1.serializers import RegisterParticipationSerializer
from gmm_mobile.v1.exceptions import GameOrCampaignDoesNotExist
from gmm_util.header import Header
from gmm_util.response import ResponseUtils
from gmm_util.permissions import MobileTokenPermission
from gmm_util.permissions import MobileTokenAuthentication
class ParticipantViewMobile(APIView):
permission_classes = (MobileTokenPermission, )
authentication_classes = (MobileTokenAuthentication, )
def post(self, request, service_id, campaign_id):
try:
environment_info = Header.get_environment_info(request)
request.data[Field.GAME_SERVICE_ID] = service_id
request.data[Field.CAMPAIGN] = campaign_id
request.data[Field.LOCATION] = environment_info
participation_serializer = RegisterParticipationSerializer(data=request.data)
participation_serializer.is_valid(raise_exception=True)
participation_serializer.save()
return ResponseUtils.created()
except Http404:
raise GameOrCampaignDoesNotExist()
serializers.py
class RegisterParticipationSerializer(serializers.ModelSerializer):
location = LocationSerializer(many=False)
campaign = serializers.IntegerField()
game_service_id = serializers.CharField(max_length=254)
class Meta:
model = Participation
fields = (Field.PK, Field.EMAIL, Field.GPG_ID, Field.DATE, Field.LOCATION, Field.INFO, Field.CAMPAIGN,
Field.GAME_SERVICE_ID, Field.GCM_ID)
read_only_fields = (Field.GCM_ID,)
test_views.py
from mock import patch
from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework import status
from rest_framework.exceptions import ValidationError
from gmm_mobile.v1.views import ParticipantViewMobile
from gmm_mobile.v1.urls import CONSULT_PARTICIPANT
from gmm_push.environment_configuration import EnvironmentConfiguration
from gmm_util.util_test import JsonObjects
class ParticipantViewMobileTests(APITestCase):
factory = APIRequestFactory()
url = reverse(PARTICIPANT_MOBILE, kwargs={'service_id': 1, 'campaign_id': 1})
def setUp(self):
self.view = ParticipantViewMobile.as_view()
#patch('gmm_mobile.v1.views.RegisterParticipationSerializer')
def test__post__invalid_data__status_400(self, mock_serializer):
# Arrange
mock_serializer.is_valid.side_effect = ValidationError({})
request = self.factory.post(
self.url,
{},
HTTP_X_ENV=JsonObjects.environment_info_1(),
HTTP_X_TOKEN=EnvironmentConfiguration.get_token(False),
format='json')
# Act
response = self.view(request, 1, 1)
# Assert
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
But when I run the test, the side_effect is not working. When I change the .is_valid in the test it has no effect on ParticipantViewMobile.post.
If I do #patch('gmm_mobile.v1.views.RegisterParticipationSerializer.is_valid') and mock_serializer.side_effect = ValidationError({}) it works, but I don't want that because there will be cases that I will need to mock more than one method, like .save and .is_valid.
I also tried to change the import styles views.py and test_views.py but it still didn't work.
Am I doind something wrong or missing anything?
EDIT 1:
I've put prints on the view to try to understand what was happening:
def post(self, request, service_id, campaign_id):
try:
environment_info = Header.get_environment_info(request)
request.data[Field.GAME_SERVICE_ID] = service_id
request.data[Field.CAMPAIGN] = campaign_id
request.data[Field.LOCATION] = environment_info
participation_serializer = RegisterParticipationSerializer(data=request.data)
print RegisterParticipationSerializer.is_valid.side_effect
print participation_serializer.is_valid.side_effect
participation_serializer.is_valid(raise_exception=True)
participation_serializer.save()
return ResponseUtils.created()
except Http404:
raise GameOrCampaignDoesNotExist()
And the output:
{}
None
So, when I create an instance of RegisterParticipationSerializer, I lost the mocked methods. How to avoid this?
Your mock doesn't work because you're mocking the class and not the instance being generated from the class. Try this:
mock_instance = Mock()
mock_instance.is_valid.side_effect = ValidationError({})
mock_serializer.return_value = mock_instance
I'm trying to generate a custom HTML and I have a value I want to pass into xml.startElement (or root if you're thinking in generic terms). How do I go about doing this?
I'm currently using django rest framework a class view and a custom renderer -
This is the beginning of the renderer -
class TESTRenderer(renderers.BaseRenderer):
media_type = 'application/xml'
format = 'xml'
charset = 'utf-8'
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
Renders *obj* into serialized XML.
"""
if data is None:
return ''
stream = StringIO()
xml = SimplerXMLGenerator(stream, self.charset)
xml.startDocument()
xml.startElement(header.data, {})
So as you can see I'm trying to pass a variable called header into the xml.startElement
Here's the view where that data lies -
class TestDetail(APIView):
permission_classes = (AllowAny,)
"""
Retrieve, update or delete a snippet instance.
"""
def get(self, request, pk, format=None):
jobmst_name = queryset1
nodmst_alias = queryset2
sysval_integer = queryset3
mst = queryset4
dtl = queryset5
dep = queryset6
trg = queryset7
name = str(jobmst_name)
master = str(nodmst_alias)
dbversion = str(sysval_integer)
header = 'job id="%s" name="%s" master="%s" dbversion="%s" xmlversion="1"' % (pk, name, master, dbversion)
jobmststring = JobmstSerializer(mst)
jobdtlstring = JobdtlSerializer(dtl)
jobdepstring = JobdepSerializer(dep, many=True)
trgjobstring = TrgjobSerializer(trg, many=True)
jobmst_serialized = {'jobmst': jobmststring.data}
jobdtl_serialized = {'jobdtl': jobdtlstring.data}
jobdep_serialized = [{'jobdep':item} for item in jobdepstring.data]
trgjob_serialized = [{'trgjob':item} for item in trgjobstring.data]
jobgroup = header, jobmst_serialized, jobdtl_serialized, jobdep_serialized, trgjob_serialized
return TestResponse(jobgroup)
The response it's using is here -
class TestResponse(HttpResponse):
"""
An HttpResponse that renders its content into XML.
"""
def __init__(self, data, **kwargs):
content = TESTRenderer().render(data)
kwargs['content_type'] = 'application/xml'
super(TestResponse, self).__init__(content, **kwargs)
Is there something I'm missing with the TestDetail where I should separate the header from the data?
maybe like this?
return TestResponse (header, jobgroup)
and then alter TestResponse to include?
def __init__(self, header, data, **kwargs):
I don't know python/django. but it seems the "Value" you are talking about are actually attributes you want to assign to the element node. I posted the same on your /r/django thread about this.