home / tils / til

Menu
  • GraphQL API

til: django_testing-django-admin-with-pytest.md

This data as json

path topic title url body html shot created created_utc updated updated_utc shot_hash slug
django_testing-django-admin-with-pytest.md django Writing tests for the Django admin with pytest-django https://github.com/simonw/til/blob/main/django/testing-django-admin-with-pytest.md I'm using [pytest-django](https://pytest-django.readthedocs.io/) on a project and I wanted to write a test for a Django admin create form submission. Here's the pattern I came up with: ```python from .models import Location import pytest def test_admin_create_location_sets_public_id(client, admin_user): client.force_login(admin_user) assert Location.objects.count() == 0 response = client.post( "/admin/core/location/add/", { "name": "hello", "state": "13", "location_type": "1", "latitude": "0", "longitude": "0", "_save": "Save", }, ) # 200 means the form is being re-displayed with errors assert response.status_code == 302 location = Location.objects.order_by("-id")[0] assert location.name == "hello" assert location.public_id == "lc" ``` The trick here is to use the `client` and `admin_user` pytest-django fixtures ([documented here](https://pytest-django.readthedocs.io/en/latest/helpers.html#fixtures)) to get a configured test client and admin user object, then use `client.force_login(admin_user)` to obtain a session where that user is signed-in to the admin. Then write tests as normal. ## Using the admin_client fixture Even better: use the `admin_client` fixture provided by `pytest-django ` which is already signed into the admin: ```python def test_admin_create_location_sets_public_id(admin_client): response = admin_client.post( "/admin/core/location/add/", # ... ``` Before finding out that this was included I implemented my own version of it: ```python import pytest @pytest.fixture() def admin_client(client, admin_user): client.force_login(admin_user) return client # Then write tests like this: def test_admin_create_location_sets_public_id(admin_client): response = admin_client.post( "/admin/core/location/add/", # ... ``` <p>I'm using <a href="https://pytest-django.readthedocs.io/" rel="nofollow">pytest-django</a> on a project and I wanted to write a test for a Django admin create form submission. Here's the pattern I came up with:</p> <div class="highlight highlight-source-python"><pre><span class="pl-k">from</span> .<span class="pl-s1">models</span> <span class="pl-k">import</span> <span class="pl-v">Location</span> <span class="pl-k">import</span> <span class="pl-s1">pytest</span> <span class="pl-k">def</span> <span class="pl-en">test_admin_create_location_sets_public_id</span>(<span class="pl-s1">client</span>, <span class="pl-s1">admin_user</span>): <span class="pl-s1">client</span>.<span class="pl-en">force_login</span>(<span class="pl-s1">admin_user</span>) <span class="pl-k">assert</span> <span class="pl-v">Location</span>.<span class="pl-s1">objects</span>.<span class="pl-en">count</span>() <span class="pl-c1">==</span> <span class="pl-c1">0</span> <span class="pl-s1">response</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>( <span class="pl-s">"/admin/core/location/add/"</span>, { <span class="pl-s">"name"</span>: <span class="pl-s">"hello"</span>, <span class="pl-s">"state"</span>: <span class="pl-s">"13"</span>, <span class="pl-s">"location_type"</span>: <span class="pl-s">"1"</span>, <span class="pl-s">"latitude"</span>: <span class="pl-s">"0"</span>, <span class="pl-s">"longitude"</span>: <span class="pl-s">"0"</span>, <span class="pl-s">"_save"</span>: <span class="pl-s">"Save"</span>, }, ) <span class="pl-c"># 200 means the form is being re-displayed with errors</span> <span class="pl-k">assert</span> <span class="pl-s1">response</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-c1">302</span> <span class="pl-s1">location</span> <span class="pl-c1">=</span> <span class="pl-v">Location</span>.<span class="pl-s1">objects</span>.<span class="pl-en">order_by</span>(<span class="pl-s">"-id"</span>)[<span class="pl-c1">0</span>] <span class="pl-k">assert</span> <span class="pl-s1">location</span>.<span class="pl-s1">name</span> <span class="pl-c1">==</span> <span class="pl-s">"hello"</span> <span class="pl-k">assert</span> <span class="pl-s1">location</span>.<span class="pl-s1">public_id</span> <span class="pl-c1">==</span> <span class="pl-s">"lc"</span></pre></div> <p>The trick here is to use the <code>client</code> and <code>admin_user</code> pytest-django fixtures (<a href="https://pytest-django.readthedocs.io/en/latest/helpers.html#fixtures" rel="nofollow">documented here</a>) to get a configured test client and admin user object, then use <code>client.force_login(admin_user)</code> to obtain a session where that user is signed-in to the admin. Then write tests as normal.</p> <h2> <a id="user-content-using-the-admin_client-fixture" class="anchor" href="#using-the-admin_client-fixture" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Using the admin_client fixture</h2> <p>Even better: use the <code>admin_client</code> fixture provided by <code>pytest-django </code> which is already signed into the admin:</p> <div class="highlight highlight-source-python"><pre><span class="pl-k">def</span> <span class="pl-s1">test_admin_create_location_sets_public_id</span>(<span class="pl-s1">admin_client</span>): <span class="pl-s1">response</span> <span class="pl-c1">=</span> <span class="pl-s1">admin_client</span>.<span class="pl-s1">post</span>( <span class="pl-s">"/admin/core/location/add/"</span>, <span class="pl-c"># ...</span></pre></div> <p>Before finding out that this was included I implemented my own version of it:</p> <div class="highlight highlight-source-python"><pre><span class="pl-k">import</span> <span class="pl-s1">pytest</span> <span class="pl-en">@<span class="pl-s1">pytest</span>.<span class="pl-s1">fixture</span>()</span> <span class="pl-k">def</span> <span class="pl-en">admin_client</span>(<span class="pl-s1">client</span>, <span class="pl-s1">admin_user</span>): <span class="pl-s1">client</span>.<span class="pl-en">force_login</span>(<span class="pl-s1">admin_user</span>) <span class="pl-k">return</span> <span class="pl-s1">client</span> <span class="pl-c"># Then write tests like this:</span> <span class="pl-k">def</span> <span class="pl-s1">test_admin_create_location_sets_public_id</span>(<span class="pl-s1">admin_client</span>): <span class="pl-s1">response</span> <span class="pl-c1">=</span> <span class="pl-s1">admin_client</span>.<span class="pl-s1">post</span>( <span class="pl-s">"/admin/core/location/add/"</span>, <span class="pl-c"># ...</span></pre></div> <Binary: 51,138 bytes> 2021-03-02T13:08:34-08:00 2021-03-02T21:08:34+00:00 2021-03-02T23:37:18-08:00 2021-03-03T07:37:18+00:00 9b8d9be51081f4bffc50faf2d80e3d9e testing-django-admin-with-pytest
Powered by Datasette · How this site works · Code of conduct