Skip to main content

Testing utils for Django-based projects

Project description

Django-testing-utils

Django-Testing-Utils is a package providing test helpers for django app testing.

build codecov PyPI version

Installation

pip install django-testing-utils

Usage

TestCase metaclass

Django 3.2 introduces setUpTestData attributes isolation, but django-testing-utils has slightly different way of resetting class attributes between tests. It collects all django model objects created in any TestCase class method and runs refresh_from_db() when necessary. It also clears fields_cache for such objects.

from django_testing_utils import mixins
from testproject.testapp import models


class SomeTestCase(mixins.BaseTestCase):
  """ Some test case that uses django models."""

  @classmethod
  def setUpTestData(cls):
    super().setUpTestData()
    # In large code django docs recommend to create common objects in 
    # this method to speedup tests setup by reusing objects in db.
    cls.project = models.Project.objects.create(name='project')

  def test_something(self):
    # in this test self.project instance is independent from other tests
    ...

Time mocking

There are multiple ways to freeze time in tests:

  • ad-hoc mocking with unittest.mock
  • freezegun library
  • any system approach that puts working with time in order

django-testing-utils provides a way to use last approach in test with some limitations:

  • Project code must work with django.utils.timezone methods only
  • All tests should inherit TimeMixin from django-testing-utils

This leads to a systematic way of datetime and timezone usage in the project and it's tests.

from django.test import TestCase
from django_testing_utils.mixins import TimeMixin, second


class MyTimeTestCase(TimeMixin, TestCase):
    @classmethod
    def setUpTestData(cls):
        # time is not mocked here yet
        ...

    def setUp(self) -> None:
        # not yet...
        super().setUp()
        # ... and here time has been frozen to `self.now`
    
    def test_something(self):
        # simulate time run
        self.now += second

Helpers for django objects

There are some helper methods to work with django objects

  • update_object - performs an UPDATE on django model in a database. This does not affect field values for an object passed to this method.
  • reload - fetches a new model instance from a database via primary key.
  • assert_object_fields fetches an actual version from a database and compares all fields with values passed as named arguments
from django_testing_utils.mixins import BaseTestCase
from testapp import models

class MyTimeTestCase(BaseTestCase):
    
    def test_something(self):
        obj = models.Project.objects.create()
        # change something in db
        self.update_object(obj, name='new')
        # fetch updated version
        new = self.reload(obj)
        # old object is untouched
        self.assertNotEqual(new.name, obj.name)
        # you could fetch and object and compare some fields in a single call 
        self.assert_object_fields(obj, name='new')

Decorators

  • override_defaults - a test case/test method decorator to change default values that are stored in app.defaults module. The idea of app.defaults is to reduce a number of rarely changed variables in django settings module by moving it to application-specific settings

  • disable_patcher - a context manager / decorator to temporarily disable some unittest.patch instances defined in TestCase instance. This breaks open/close principle but allows postponing tests refactoring when some mocks are too generic.

from django.test import TestCase
from django.utils import timezone
from django_testing_utils.mixins import TimeMixin
from django_testing_utils.utils import override_defaults, disable_patchers
from testapp import defaults
import testapp

class MyTestCase(TimeMixin, TestCase):
    
    @override_defaults(testapp.__name__, setting_1=42)
    def test_setting_value(self):
        self.assertEqual(defaults.setting_1, 42)
        
    @disable_patchers('now_patcher')
    def test_real_time(self):
        # now patcher from TimeMixin is now disabled
        with disable_patchers(self.timezone_datetime_patcher):
          # timezone.datetime patcher is not also disabled
          self.assertNotEqual(timezone.now(), timezone.now())

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-testing-utils-0.7.0.tar.gz (9.1 kB view details)

Uploaded Source

Built Distribution

django_testing_utils-0.7.0-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file django-testing-utils-0.7.0.tar.gz.

File metadata

  • Download URL: django-testing-utils-0.7.0.tar.gz
  • Upload date:
  • Size: 9.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.12.2

File hashes

Hashes for django-testing-utils-0.7.0.tar.gz
Algorithm Hash digest
SHA256 c1eceeede958249bdc5a1fc264786fc59c6e026954dbafcb97bc9c514ee33f9b
MD5 b65c096822f1e25d3c584c11a995ae89
BLAKE2b-256 bcb35af395b4dc45889c285693554b5f4ba50d4bd6c4e90d40d20466dd9f90a8

See more details on using hashes here.

File details

Details for the file django_testing_utils-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_testing_utils-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 70c67b82cdb35fd49ef3b0a63ad6c97f41516449933189e413ab88693841ae42
MD5 81d36976bbc507a935674791d6c477ab
BLAKE2b-256 f365d087afdf9a18a216e9f6a70f829bece704d89399b98ebbbea2a6adfe6d85

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page