Skip to main content

drf-test-generator

Pypi Version Supported Python Versions Supported Django Versions License

Django Tests Codecov pre-commit.ci Code Style

A Django Package that generates basic tests for Django REST Framework. It can generate both unittest and pytest Style tests for all ViewSets in a Django REST Framework router.

Features

  • Generates tests for all ViewSets in a Django REST Framework router
  • Generates tests for all custom actions in a ViewSet
  • Generates tests for all HTTP methods in a ViewSet
  • Supports test generation for both pytest and unittest

Requirements

  • Python 3.8+
  • Django 4.2+
  • Django REST Framework 3.12+

Installation

pip install drf-test-generator

Setup

Add drf_test_generator to your INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    # ...
    "drf_test_generator",
]

Note: This is required for the Django Management Command. You can remove it from INSTALLED_APPS once you have generated the tests.

Generate Tests

Django Management Command

You can generate tests using the Django Management Command:

python manage.py generate_viewset_tests -r api.urls.router

Note: Currently this package only supports test generation for ViewSets that are registered in a router.

Django Management Command Options

-r or --router (REQUIRED)

The dotted path to the REST framework url router. This is the router that contains the ViewSets you want to generate tests for.

Example: --router api.urls.router

--test-base-class

The dotted path to the test base class. This is the class that your tests will inherit from. If not provided, the tests will inherit from rest_framework.test.APITestCase.

Example: --test-base-class tests.base.MyCustomTest

--namespace

The namespace to use for the URLs (e.g: api_v1:posts-list ). If not provided, no namespace will be used.

Example: --namespace api_v1

--output-file

The path to the output file. If not provided, the tests will be printed to the console.

Example: --output-file tests.py

--select-viewsets

A list of ViewSets to generate tests for. If not provided, tests will be generated for all ViewSets in the router.

Example: --select-viewsets PostViewSet CommentViewSet

--variant

The test variant to generate. Options: pytest, unittest. If not provided, unittest will be used.

Example: --variant pytest

--pytest-markers

A list of pytest markers to add to the generated tests. If not provided, only the @pytest.mark.django_db marker will be added.

Example: --pytest-markers pytest.mark.ignore_template_errors pytest.mark.urls('myapp.test_urls')

--pytest-fixtures

A list of pytest fixtures to add to the generated tests. If not provided, only the client fixture will be added.

Example: --pytest-fixtures django_user_model

Examples Usage

For the following code

# api/views.py
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response


class PostViewSet(viewsets.ModelViewSet):
    # ...
    @action(detail=False, methods=["get", "post"], url_path="custom-action")
    def custom_action(self, request):
        return Response()

    @action(detail=True, methods=["get", "options", "put"], url_path="new-action")
    def custom_action2(self, request):
        return Response()


# api/urls.py
from rest_framework import routers

router = routers.DefaultRouter()

router.register("posts", PostViewSet, basename="post")

For Unittest

Run Command

python manage.py generate_viewset_tests -r api.urls.router

Output

from django.urls import reverse

from rest_framework import status

from rest_framework.test import APITestCase


class PostViewSetTests(APITestCase):
    def test_post_list_get(self):
        url = reverse("post-list")
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_create_post(self):
        url = reverse("post-list")
        response = self.client.post(url, data={})
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_post_custom_action_get(self):
        url = reverse("post-custom-action")
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_custom_action_post(self):
        url = reverse("post-custom-action")
        response = self.client.post(url, data={})
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_post_retrieve_get(self):
        url = reverse("post-detail", kwargs={"pk": None})
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_update_put(self):
        url = reverse("post-detail", kwargs={"pk": None})
        response = self.client.put(url, data={})
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_partial_update_patch(self):
        url = reverse("post-detail", kwargs={"pk": None})
        response = self.client.patch(url, data={})
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_destroy_delete(self):
        url = reverse("post-detail", kwargs={"pk": None})
        response = self.client.delete(url)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_post_custom_action2_get(self):
        url = reverse("post-custom-action2", kwargs={"pk": None})
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_custom_action2_options(self):
        url = reverse("post-custom-action2", kwargs={"pk": None})
        response = self.client.options(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_custom_action2_put(self):
        url = reverse("post-custom-action2", kwargs={"pk": None})
        response = self.client.put(url, data={})
        self.assertEqual(response.status_code, status.HTTP_200_OK)

For Pytest

Run Command

python manage.py generate_viewset_tests -r api.urls.router --variant pytest

Output

from django.urls import reverse

from rest_framework import status

import pytest

# PostViewSet Tests


@pytest.mark.django_db
def test_post_list_get(client):
    url = reverse("post-list")
    response = client.get(url)
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_create_post(client):
    url = reverse("post-list")
    response = client.post(url, data={})
    assert response.status_code == status.HTTP_201_CREATED


@pytest.mark.django_db
def test_post_custom_action_get(client):
    url = reverse("post-custom-action")
    response = client.get(url)
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_custom_action_post(client):
    url = reverse("post-custom-action")
    response = client.post(url, data={})
    assert response.status_code == status.HTTP_201_CREATED


@pytest.mark.django_db
def test_post_retrieve_get(client):
    url = reverse("post-detail", kwargs={"pk": None})
    response = client.get(url)
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_update_put(client):
    url = reverse("post-detail", kwargs={"pk": None})
    response = client.put(url, data={})
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_partial_update_patch(client):
    url = reverse("post-detail", kwargs={"pk": None})
    response = client.patch(url, data={})
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_destroy_delete(client):
    url = reverse("post-detail", kwargs={"pk": None})
    response = client.delete(url)
    assert response.status_code == status.HTTP_204_NO_CONTENT


@pytest.mark.django_db
def test_post_custom_action2_get(client):
    url = reverse("post-custom-action2", kwargs={"pk": None})
    response = client.get(url)
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_custom_action2_options(client):
    url = reverse("post-custom-action2", kwargs={"pk": None})
    response = client.options(url)
    assert response.status_code == status.HTTP_200_OK


@pytest.mark.django_db
def test_post_custom_action2_put(client):
    url = reverse("post-custom-action2", kwargs={"pk": None})
    response = client.put(url, data={})
    assert response.status_code == status.HTTP_200_OK

License

The code in this project is released under the MIT License.

Metadata

Release files for drf-test-generator 0.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for drf-test-generator 0.0.6
File Size Uploaded Provenance Actions
drf_test_generator-0.0.6.tar.gz 12.3 kB Without provenance Details for drf_test_generator-0.0.6.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for drf-test-generator 0.0.6
File Interpreter ABI Platform Actions
drf_test_generator-0.0.6-py3-none-any.whl Python 3 none any Details for drf_test_generator-0.0.6-py3-none-any.whl

Total release size: 21.6 kB

Release files / drf_test_generator-0.0.6.tar.gz

Download URL drf_test_generator-0.0.6.tar.gz
Size 12.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e487d23d98de22559d2c69d4bd915b373b0d5252fa36aedf4dd09e1fa458b6b8
BLAKE2b-256 checksum
How to use checksums
32cd3a6caca1f845ab1c76963c5f87aef9df09dca769bae173674240ec9e2fa0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.5

Release files / drf_test_generator-0.0.6-py3-none-any.whl

Download URL drf_test_generator-0.0.6-py3-none-any.whl
Size 9.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ed1ca1bbb7fd00613889802dcf55ba5c4a11b5cd8fa2f1f91af1979c8023fe0f
BLAKE2b-256 checksum
How to use checksums
29d82ec621fe4fcd3c81e6d208e684d54beaf25f40b56c6958b8bffa73f825e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.5

Security for drf-test-generator 0.0.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.6 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page