Skip to main content

A Django test mixin that captures and displays SQL query diffs between test runs, helping to track database-related changes in your tests.

Project description

django-sql-test

Prevent SQL regressions, detect N+1 queries, and visualize query diffs in your Django tests. A test mixin that captures, snapshots, and diffs all executed SQL queries in your test output.

Package version Supported Python versions License
$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
 ...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Queries diff:
- SELECT polls_choice.id FROM polls_choice
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
  SELECT COUNT(*) AS __count FROM polls_question

Table of Contents

Requirements

  • Django >= 4.0
  • Python >= 3.9

Installation

pip install django-sql-test

Quickstart

In your test.py just import NumNewQueriesMixin and add it as a parent:

from django.test import TestCase
from django_sql_test import NumNewQueriesMixin

class FooTest(NumNewQueriesMixin, TestCase):
    def test_bar(self):
        with self.assertNumNewQueries(2):
            response = self.client.get(self.url)

        self.assertEqual(response.status_code, 200)

What you got before adding NumNewQueriesMixin:

$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
  ...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Captured queries were:
1. SELECT "polls_choice"."id" FROM "polls_choice" WHERE "polls_choice"."votes" >= 0
2. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
3. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
4. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
5. SELECT COUNT(*) AS "__count" FROM "polls_question"

What you get after adding NumNewQueriesMixin:

$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
 ...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Queries diff:
- SELECT polls_choice.id FROM polls_choice
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
  SELECT COUNT(*) AS __count FROM polls_question

Configuration

Configure via your Django settings:

Setting Default Description
SQL_TEST_GENERALIZED_DIFF True Hides SQL query parameters by replacing them with placeholders.
SQL_TEST_DIFF_ONLY False If set to True, shows only SQL queries that were added or removed; otherwise, shows all queries.
SQL_TEST_DIFF_NEW_COLOR "\033[1;32m" Color code for newly added SQL queries (green).
SQL_TEST_DIFF_OLD_COLOR "\033[1;31m" Color code for removed SQL queries (red).
SQL_TEST_DIFF_DEFAULT_COLOR "\033[0m" Base console color code for unchanged SQL queries.
SQL_TEST_ENGINE "file" Engine used to store the last successful SQL queries. Default "file" engine stores data in the file from SQL_TEST_ENGINE_SETTINGS["filename"], or in .django_sql_test_queries at the project root if not set. You can implement a custom engine by inheriting from django_sql_test.engine.Engine, overriding its methods, and specifying its full path, e.g., SQL_TEST_ENGINE = "path.to.YourEngine".
SQL_TEST_ENGINE_SETTINGS {} Dictionary of settings passed to the engine's constructor. For the default "file" engine, you can pass the path to the file where queries will be stored in JSON format.

SQL_TEST_GENERALIZED_DIFF

If set to True:

Queries diff:
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N

If set to False:

Queries diff:
+ SELECT "polls_choice"."id" FROM "polls_choice" WHERE "polls_choice"."votes" >= 0

API Reference

NumNewQueriesMixin

Method Description
assertNumNewQueries Works just like django.test.testcases.TransactionTestCase.assertNumQueries, but also prints the diff of queries compared to the last successful run, if any.
assertNumQueries Acts like assertNumNewQueries. It can be used if you don’t want to replace every occurrence of assertNumQueries with assertNumNewQueries in your tests. Simply inherit from it in your test class, for example: class PaginatorsTestCase(NumNewQueriesMixin, ViewTestCase), and everything will work out of the box.

Contributing

We welcome contributions! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/YourFeature)
  3. Write tests and ensure coverage
  4. Run and pass:
    poetry run isort -c --diff --settings-file pyproject.toml .
    poetry run black --diff --config pyproject.toml --check .
    poetry run python runtests.py
    
  5. Submit a pull request

License

This project is licensed under the MIT License. See LICENSE for details.

Changelog

All notable changes are documented on the Releases page.

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_sql_test-0.3.0.tar.gz (5.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_sql_test-0.3.0-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

File details

Details for the file django_sql_test-0.3.0.tar.gz.

File metadata

  • Download URL: django_sql_test-0.3.0.tar.gz
  • Upload date:
  • Size: 5.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.13.2 Darwin/24.5.0

File hashes

Hashes for django_sql_test-0.3.0.tar.gz
Algorithm Hash digest
SHA256 28d6dd56870b043ffc57da8cbd6a08a551e09203c5f47d66c6ac1950b7d36c86
MD5 ad328580adb47fd49e8f32ab22080768
BLAKE2b-256 0145a68301650a159a3c7d3d503bd687e2697b78c8dc0ec46b2ea1c4892685f1

See more details on using hashes here.

File details

Details for the file django_sql_test-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: django_sql_test-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 7.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.1 CPython/3.13.2 Darwin/24.5.0

File hashes

Hashes for django_sql_test-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1051eea2bc2277a84f9076343b986cf4b22451d4c4e6b2bd8e5e4c2ecd98cbd3
MD5 991c627d13aeee406e16445f2a7cb7db
BLAKE2b-256 33fe8b722e9690d6d0a31919e9e414ab39ab89f16a59a44b2af45cb094d1daf8

See more details on using hashes here.

Supported by

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