I have this fixture , and I want to make it global , where should I put it in my django project
#pytest.fixture
def auth_client(user = None):
if(user is None):
user = User.objects.create()
client = APIClient()
client.login(username=user.username, password=user.password)
return client
thanks in advance.
I found the answer, just create a conftest.py in the main directory and put in it the fixture.
Related
For my Django project, I'm implementing RestAPI using DRF. To preserve some variables needed by two APIs, I wish to use a Django session. However, when I called Api2 after setting the session on Api1, it was None.
Has anybody encountered it before? Thank you very much for your assistance!
Here is an example of my API code:
from rest_framework import viewsets
class BaseViewSet(viewsets.ViewSet):
#action(methods="post")
def lookup(self, request):
request.session['abc'] = 1
request.session.modified = True
request.session.save()
print(request.session.session_key) # p02sr0qlnzntagfkf9ekm8f8km4w82t4
return = {}
#action(methods="post")
def login(self, request):
print(request.session.session_key) # None, it should be key p02sr0qlnzntagfkf9ekm8f8km4w82t4
print(request.session.get('abc') # None
data = {}
I started noticing that the patch method in django rest framework doesn't actually trigger signals, post methods seem to work fine. This is what I have:
#receiver(signals.pre_save, sender=Example)
def populate_time_fields_based_on_state(sender, **kwargs):
example = kwargs.get('instance')
if example.start_datetime is None and example.projected_end_datetime is None and example.state.label == 'Assigned':
example.start_datetime = datetime.datetime.now()
example.projected_end_datetime = example.created_datetime + datetime.timedelta(
days=example.som_field)
example.save()
And I'm testing this via:
client = APIClient()
client.patch(f'/api/example/1/', {'state': 'Assigned'})
Is there a way to tell it to trigger the signal? Do I need to override the update method in my serializer? I'm trying this:
def partial_update(self, request, *args, **kwargs):
response = super().partial_update(request, *args, **kwargs)
instance = self.get_object()
instance.save()
return response
But it's quite hacky
In your app directory there should be an apps.py, see the docs for the format of it.
Generally it ends up looking like the following, as opposed to the example where they wire up the signal manually. Note that I have a "project/apps/" structure here, but just change the module name depending on where the files actually live:
#project/apps/my_app/__init__.py
default_app_config = 'project.apps.my_app.apps.MyAppConfig'
#project/apps/my_app/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "project.apps.my_app"
verbose_name = "MyApp"
def ready(self):
from project.apps.my_app import signals
# ... other init &/or logging
Note: Feel free to delete the line in init.py, and play with the name in the app config. I'm not sure how critical they actually are
I am migrating the UnitTests of a Django app to py.test, but in the UnitTests they make use of factory-boy to create instances of django.contrib.auth.models.User. how can this be done with pytest-factory-boy?
Creating a user in py.test, without to need for a factory is quite simple.
py.test already has a helper containing a builtin Django admin_user and admin_client fixture as explained here.
Here some code, for usage in your conftest.py to create a normal user:
import pytest
from django.contrib.auth.models import User
#pytest.fixture
def user_client(client):
"""
User fixture for tests with unprivileged user
"""
user = User.objects.create_user(
username='user',
password='pass',
first_name='Normal',
last_name='User'
)
response = client.post(reverse('login'), data={'username': 'user', 'password': 'pass'})
assert response.status_code == 302
return user_client
I'm working on my first project which uses Django REST Framework, and I'm having issues testing the API. I'm getting 403 Forbidden errors instead of the expected 200 or 201. However, the API works as expected.
I have been going through DRF Testing docs, and it all seems straightforward, but I believe my client is not being logged in. Normally in my Django projects I use a mixture of factory boy and django webtest which I've had a lot of happy success with. I'm not finding that same happiness testing the DRF API after a couple days of fiddling around.
I'm not sure if this is a problem relating to something I'm doing wrong with DRF APITestCase/APIClient or a problem with the django test in general.
I'm just pasting the following code and not posting the serializers/viewsets because the API works in the browser, it seems I'm just having issues with the APIClient authentication in the APITestCase.
# settings.py
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
# tests.py
from django.test import TestCase
from rest_framework.test import APITestCase, APIClient
from accounts.models import User
from .factories import StaffUserFactory
class MainSetUp(TestCase):
def setUp(self):
self.user = StaffUserFactory
self.api_root = '/api/v0/'
self.client = APIClient()
class APITests(MainSetUp, APITestCase):
def test_create_feedback(self):
"""
Ensure we can create a new account object.
"""
self.client.login(username='staffuser', password='staffpassword')
url = '%sfeedback/' % self.api_root
data = {
'feedback': 'this is test feedback'
}
response = self.client.post(url, data, user=self.user)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data, data)
# factories.py
from factory.django import DjangoModelFactory
from django.contrib.auth import get_user_model
User = get_user_model()
class UserFactory(DjangoModelFactory):
class Meta:
model = User
class StaffUserFactory(UserFactory):
username = 'staffuser'
password = 'staffpassword'
email = 'staff#email.com'
first_name = 'Staff'
last_name = 'User'
is_staff = True
I've never used DjangoModelFactory before, but it appears that you have to call create after setting your user to the StaffUserFactory. http://factoryboy.readthedocs.org/en/latest/_modules/factory/django.html#DjangoModelFactory
class MainSetUp(TestCase):
def setUp(self):
self.user = StaffUserFactory
self.user.create()
self.api_root = '/api/v0/'
self.client = APIClient()
I bet your User's password is not being set properly. You should use set_password. As a start, trying changing your setUp to this:
def setUp(self):
self.user = StaffUserFactory
self.user.set_password('staffpassword')
self.user.save() # You could probably omit this, but set_password does't call it
self.api_root = '/api/v0/'
self.client = APIClient()
If that works, you probably want to override _generate() in your factory to add that step.
Another thing to check would be that SessionAuthentication is in your DEFAULT_AUTHENTICATION_CLASSES setting.
I think you must instantiate the Factory to get real object, like this:
self.user = StaffUserFactory()
Hope that help.
Moreover, you don't need to create a seperate class for staff, just set is_staff=True is enough. Like this:
self.user = UseFactory(is_staff=True)
I'm trying to access the request.user object when testing my app using django's client class.
from django.test import TestCase
from django.test.client import Client
class SomeTestCase(TestCase):
def setUp(self):
self.client = Client()
self.client.login( username="foo", password="bar")
def test_one(self):
response = self.client.get("/my_profile/")
self.fail( response.request.user )
This will obviously fail, but it fails because response.request doesn't have a user attribute.
AttributeError: 'dict' object has no attribute 'user'
Is there any way to access the user object from the client instance? I want to do this in order to check if some test user's data is properly rendered. I can try to tackle this by setting up all the necessary info during setUp, but before I do that I wanted to check if I'm not just missing something.
This may seem a roundabout way of doing it but it can be useful.
Use RequestFactory, its pretty straightforward. It imitates the request object.
from django.test import TestCase, RequestFactory
from django.test.client import Client
from django.contrib.auth.models import User
class SomeTestCase(TestCase):
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
self.user = User.objects.create_user(
username='foo', email='foo#bar',
password='bar')
def test_one(self):
self.client.login( username="foo", password="bar")
request = self.factory.get("/my_profile/")
request.user = self.user
#rest of your code
def tearDown(self):
self.user.delete()
I hope that was helpful.
Use response.context['user'].
User is automatically available in the template context if you use RequestContext. See auth data in templates doc.
Otherwise i believe you should just query it:
def test_one(self):
response = self.client.get("/my_profile/")
user = User.objects.get(username="foo")
self.fail( user.some_field == False )