Django test client post data - django

The problem has been solved thanks to Thaian, by adding a login to the beginning of the 'test_create' function, as you need to be logged in on this site to use the createview
I am currently writing a test for a createview and I am unable to post data to it.
The object being tested has the following model
class Role(models.Model):
name = models.CharField(max_length=255)
linked_tenant = models.ForeignKey(Tenant, blank=True, null=True)
And is used in the following (generic) view
class RolCreate(TenantRootedMixin, CreateView):
model = RolTemplate
form_class = RoleForm
def get_form_kwargs(self):
kwargs = super(RolCreate, self).get_form_kwargs()
kwargs['linked_tenant'] = self.request.tenant
return kwargs
def form_valid(self, form):
form.instance.linked_tenant = self.kwargs.get('tenant')
return super(RolCreate, self).form_valid(form)
def get_success_url(self, **kwargs):
return reverse('rol_list', args=[self.request.tenant.slug])
And this is the test that I am using.
class RolCreate_tests(TestCase):
def setUp(self):
self.tenant = get_tenant()
self.role = get_role(self.tenant)
self.client = Client(HTTP_HOST='tc.tc:8000')
self.user = get_user(self.tenant)
def test_create(self):
response = self.client.post(reverse('rolcreate'), {'name' : 'new_object'})
self.assertEqual(response.status_code, 302)
test_against = Role.objects.get(name='new_object')
self.assertEqual(test_against, self.tenant)
The assertion that throws the error is the 'get' request at the end.
DoesNotExist: Role matching query does not exist.
So the object is not created, yet the test does validate the 302 view, meaning a post is being made. I do not understand why this test is failing to do what it should. Could someone here help me?
=====
After Thaians suggestions I got the following values:
(Pdb) print(self.client.post)
<bound method Client.post of <django.test.client.Client object at 0x10f20da50>>
Pdb) response
<HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/accounts/login/?next=/my/role/create/">
(Pdb) print(response)
Vary: Cookie
Content-Length: 0
Content-Type: text/html; charset=utf-8
Location: /accounts/login/?next=/my/role/create/

Did you print response and check what return maybe?
Good idea is to run tests with PDB.
def test_create(self):
response = self.client.post(reverse('rolcreate'), {'name': 'new_object'})
import pdb; pdb.set_trace()
self.assertEqual(response.status_code, 302)
test_against = Role.objects.get(name='new_object')
self.assertEqual(test_against, self.tenant)
add import pdb;pdb.set_trace() in your test and then check self.client.post().
So please paste what response contain.

Related

DRF Viewset test method

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

Django REST testing - how to specify pk argument referring to the model instance created in setUp function

I have a model "Article" and I want to test if authorized user can GET an individual article.
The testing class is:
class TestPost(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create_user(
username='Name', email='test#company.com', password='secret')
self.article = Article.objects.create(
author = 'Author', title = 'Article title', body = 'Body content ...')
def test_detail_user(self):
request = self.factory.get(reverse('article_id', kwargs={'pk': 1}))
request.user = self.user
response = ArticleDetail.as_view()(request, pk=1)
self.assertEqual(response.status_code, 200,
f'Expected Response Code 200 - OK, received {response.status_code} instead.')
The URL pattern is:
path('<int:pk>/', ArticleDetail.as_view(), name = 'article_id'),
And when running tests I get the following error:
f'Expected Response Code 200 - OK, received {response.status_code} instead.')
AssertionError: 404 != 200 : Expected Response Code 200 - OK, received 404 instead.
I suppose the problem is in the specified 'pk', but I cannot figure out how to specify pk without stating an exact figure of 1. How can I refer to the article created in setUp function instead?
I may be misunderstanding, but you should be able to reference it by simply doing something like:
def test_detail_user(self):
article_id = self.article.pk
...
# the rest of your code here using article_id as the id of
# the article you are retrieving

How to make a POST request to the end point, in views in django for chatterbot?

i am new to django!
I want to make a chatterbot chatbot in my website, for which i need to make a POST request in views. I have created a model. I am using mysql database for this.
I have visited github and other website and finally got a code, but it doesn't have the POST request
this is my models.py:
class Response(models.Model):
statement = models.ForeignKey(
'Statement',
related_name='in_response_to',
on_delete=False
)
response = models.ForeignKey(
'Statement',
related_name='+',
on_delete=False
)
unique_together = (('statement', 'response'),)
occurrence = models.PositiveIntegerField(default=0)
def __str__(self):
s = self.statement.text if len(self.statement.text) <= 20 else self.statement.text[:17] + '...'
s += ' => '
s += self.response.text if len(self.response.text) <= 40 else self.response.text[:37] + '...'
return s
this is where i need to make a POST request in views.py
def post(self, request, *args, **kwargs):
response = Response.objects.all()
if request.is_ajax():
input_data = json.loads(request.read().decode('utf-8'))
else:
input_data = json.loads(request.body.decode('utf-8'))
self.validate(input_data)
response_data = self.chatterbot.get_response(input_data)
return JsonResponse(response, response_data, status=200)
def get(self, request, *args, **kwargs):
data = {
'detail': 'You should make a POST request to this endpoint.',
'name': self.chatterbot.name,
'recent_statements': self._serialize_recent_statements()
}
# Return a method not allowed response
return JsonResponse(data, status=405)
If you're using django rest framework (DRF), i recommend you start by doing QuickStart and then Serialization steps. DRF has a really good documentation and in the Serialization you could find how to make a POST request by defining:
Models
Serializers
Api
Routers

Django testing an update post

I receive this message "feed.models.Post.DoesNotExist: Post matching query does not exist." I believe it to be in the UpdatePost class I dont understand as there is a post created with an id of one. Why is this? Edit : I've added delete to fully test CRUD functionality
from django.test import TestCase, SimpleTestCase
from django.contrib.auth.models import User
from django.urls import reverse
from feed.models import Post
class Setup_Class(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='jtur', email='jtur#accenture.com', password='onion')
user = User.objects.first()
Post.objects.create(title='test', content='more testing', author=user)
class PostTests(Setup_Class):
def test_content(self):
post = Post.objects.get(id=1)
expected_post_title = f'{post.title}'
expected_post_content = f'{post.content}'
self.assertEquals(expected_post_title, 'test')
self.assertEquals(expected_post_content, 'more testing')
def test_post_list_view(self):
response = self.client.get(reverse('feed-home'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'more testing')
self.assertTemplateUsed(response, 'feed/home.html')
class UpdatePost(Setup_Class):
def test_post_update(self):
post = Post.objects.first()
post.title = "This has been changed"
expected_post_title = f'{post.title}'
self.assertEquals(expected_post_title, 'This has been changed')
def test_post_updated_view(self):
response = self.client.get(reverse('feed-home'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'This has been changed')
self.assertTemplateUsed(response, 'feed/home.html')
class DeletePost(Setup_Class):
def test_post_delete(self):
post = Post.objects.first()
post.delete()
val = False
if post is None:
val = True
else:
val = False
self.assertTrue(val)
def test_post_list_view(self):
response = self.client.get(reverse('feed-home'))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, 'test')
self.assertTemplateUsed(response, 'feed/home.html')
There's no reason to assume the post created in your setUp method will have id=1. In fact, it probably won't after the first run of your tests. Even though the database is emptied after each run, the sequences are usually not reset.
You should get the first post with Post.objects.first() instead.
(Note however that your test_content and test_post_update methods are pretty pointless; they only call native Django functionality, which you don't need to test. Your tests should be concerned with testing your app's functionality, such as views that update or display the posts.)

Django REST Framework - unittest client failing to resolve hyperlinks relation for POST

I have this test:
class AttributeTest(APITestCase):
def setUp(self):
user1 = User.objects.create(pk=1, username='pepa', email='ads#asasd.cz', is_active=True, is_staff=True)
user1.set_password('mypass')
user1.save()
self.c1 = Campaign.objects.create(pk=1, owner=user1, project_name='c1')
def test(self):
campaign_url = 'http://testserver/api/campaigns/{}/'.format(self.c1.pk)
self.client.login(username='pepa', password='mypass')
data = {
"label": "something_here",
"parent_campaign": campaign_url,
}
# campaign clearly exists (created in setUp) and GET retrieve it:
assert self.client.get(campaign_url).json()['project_name'] == 'c1'
# I can even try it myself using pdb
# but this doesn't work - response return 400 Bad Request
# complaining about the very same hyperlink I can GET above
response = self.client.post('/api/keys', data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
but when run, it fails with {'parent_campaign': ['Invalid hyperlink - No URL match.']}.
When I try using curl or browsable API (outside the test environment), everything works as expected.
My serializer corresponding to the /api/keys:
class AttributeSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='api:key-detail')
parent_campaign = serializers.HyperlinkedRelatedField(
view_name='api:campaign-detail',
lookup_field='cid',
queryset=Campaign.objects.all())
def _get_user_campaigns(self):
user = self.context['view'].request.user
return Campaign.objects.filter(owner=user)
def get_fields(self, *args, **kwargs):
fields = super(AttributeSerializer, self).get_fields(*args, **kwargs)
fields['parent_campaign'].queryset = self._get_user_campaigns()
return fields
class Meta:
model = Key
fields = ("id", 'url', "label", 'parent_campaign')
Using serializer directly:
(Pdb) from api.attribute.serializers import AttributeSerializer
(Pdb) ser = AttributeSerializer(data=data)
(Pdb) ser.is_valid()
True
(Pdb) ser.save()
<Key: Something1 | MAROO | CID: lrvyw93>
Try reversing your url name and passing c1.pk as a url parameter, not just formatting it into your url:
from rest_framework.reverse import reverse
campaign_url_name = 'api:campaign-detail' # Use URL name instead of raw URL path
response = self.client.get(reverse(campaign_url_name, kwargs={'pk': self.c1.pk}))
I don't know why, but the results of tests had to be somehow cached. I restarted the PC and it worked with exactly the same commit. Solved.