Skip to content

Document use of authenticated client and django_user_model #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 25, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 43 additions & 61 deletions docs/helpers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on what marks are and for notes on using_ them.
.. :py:function:: pytest.mark.django_db:

This is used to mark a test function as requiring the database. It
will ensure the database is setup correctly for the test. Each test
will ensure the database is set up correctly for the test. Each test
will run in its own transaction which will be rolled back at the end
of the test. This behavior is the same as Django's standard
`django.test.TestCase`_ class.
Expand Down Expand Up @@ -137,12 +137,23 @@ Example
response = client.get('/')
assert response.content == 'Foobar'

To use `client` as an authenticated standard user, call its `login()` method before accessing a URL:

::

def test_with_authenticated_client(client, django_user_model):
username = "user1"
password = "bar"
django_user_model.objects.create(username=username, password=password)
client.login(username=username, password=password)
response = client.get('/private')
assert response.content == 'Protected Area'


``admin_client`` - ``django.test.Client`` logged in as admin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

An instance of a `django.test.Client`_,
that is logged in as an admin user.
An instance of a `django.test.Client`_, logged in as an admin user.

Example
"""""""
Expand All @@ -153,36 +164,49 @@ Example
response = admin_client.get('/admin/')
assert response.status_code == 200

As an extra bonus this will automatically mark the database using the
``django_db`` mark.
Using the `admin_client` fixture will cause the test to automatically be marked for database use (no need to specify the
``django_db`` mark).

``admin_user`` - a admin user (superuser)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

An instance of a superuser, with username "admin" and password "password" (in
case there is no "admin" user yet).

As an extra bonus this will automatically mark the database using the
``django_db`` mark.
Using the `admin_user` fixture will cause the test to automatically be marked for database use (no need to specify the
``django_db`` mark).


``django_user_model``
~~~~~~~~~~~~~~~~~~~~~

The user model used by Django. This handles different versions of Django.
A shortcut to the User model configured for use by the current Django project (aka the model referenced by
`settings.AUTH_USER_MODEL`). Use this fixture to make pluggable apps testable regardless what User model is configured
in the containing Django project.

Example
"""""""

::

def test_new_user(django_user_model):
django_user_model.objects.create(username="someone", password="something")


``django_username_field``
~~~~~~~~~~~~~~~~~~~~~~~~~

The field name used for the username on the user model.
This fixture extracts the field name used for the username on the user model, i.e. resolves to the current
``settings.USERNAME_FIELD``. Use this fixture to make pluggable apps testable regardless what the username field
is configured to be in the containing Django project.

``db``
~~~~~~~

.. fixture:: db

This fixture will ensure the Django database is set up. This only
required for fixtures which want to use the database themselves. A
This fixture will ensure the Django database is set up. Only
required for fixtures that want to use the database themselves. A
test function should normally use the :py:func:`~pytest.mark.django_db`
mark to signal it needs the database.

Expand Down Expand Up @@ -242,7 +266,7 @@ Example
``mailoutbox``
~~~~~~~~~~~~~~~~~~~~~~~~~

A clean mail outbox where Django emails are being sent to.
A clean email outbox to which Django-generated emails are sent.

Example
"""""""
Expand All @@ -261,65 +285,23 @@ Example
assert list(m.to) == ['[email protected]']


Environment autouse fixtures
----------------------------
Automatic cleanup
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this title because they appear to the end developer not as fixtures but as general features of pytest-django.

-----------------

pytest-django provides some pytest fixtures that are of autouse
nature. They provide functionality to assure a clean environment
pytest-django provides some functionality to assure a clean and consistent environment
during tests.


Clearing of site cache
~~~~~~~~~~~~~~~~~~~~~~

If ``django.contrib.sites`` is in your INSTALLED_APPS, Site cache will
be cleared for each test to avoid hitting the cache and cause wrong Site
be cleared for each test to avoid hitting the cache and causing the wrong Site
object to be returned by ``Site.objects.get_current()``.


Clearing of mail.outbox
~~~~~~~~~~~~~~~~~~~~~~~

``mail.outbox`` will be cleared for each pytest, to give tests a empty
mailbox. It is however more pytestic to use the ``mailoutbox`` fixture
to access ``mail.outbox``.


Examples
--------


Example with ``rf``, ``admin_user``, fixture and class-based views
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this example because it was not at all clear how it demonstrates the automatic cleanup discussed in this section. If an example is needed, hopefully we can come up with something more succinct and demonstrative.

""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

::

import pytest

from django.core.urlresolvers import reverse
from myapp.models import Thing
from myapp.views import ThingDetailView

@pytest.fixture
def thing(admin_user):
(thing_object, created) = Thing.objects.get_or_create(name="test",
created_by=admin_user)
return thing_object

def test_detail_view_logged_in(rf, admin_user, thing):
# set kwargs for reverse and for view
kwargs_thing = {
'pk': thing.id,
}

url = reverse("thing_detail", kwargs=kwargs_thing)

# bind url to request factory
request = rf.get(url)

# set user in request to admin_user
request.user = admin_user

# creates response, given request and kwargs needed for view
response = ThingDetailView.as_view()(request, **kwargs_thing)
assert response.status_code == 200
``mail.outbox`` will be cleared for each pytest, to give each new test an empty
mailbox to work with. However, it's more "pytestic" to use the ``mailoutbox`` fixture described above
than to access ``mail.outbox``.