Pytest-django: рдбреЗрдЯрд╛ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╕реЗ рдбреЗрдЯрд╛ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реБрдП live_server рдлрд╝рд┐рдХреНрд╕реНрдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд░реАрдХреНрд╖рдг

рдХреЛ рдирд┐рд░реНрдорд┐рдд 14 рдЕрдкреНрд░реИрд▓ 2016  ┬╖  21рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: pytest-dev/pytest-django

рдореИрдВрдиреЗ рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдкреБрди: рдкреЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкрд░реАрдХреНрд╖рдг рдХреЗрд╕ рдмрдирд╛рдпрд╛ рд╣реИ https://github.com/ekiro/case_pytest/blob/master/app/tests.py рдЬреЛ рджреВрд╕рд░реЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдмрд╛рдж live_server рд╕реНрдерд┐рд░рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
MyModel рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдореЗрдВ RunPython рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ live_server рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА рднреА рдкрд░реАрдХреНрд╖рдг рдХреЗ рдмрд╛рдж, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЛ рдЫреЛрдЯрд╛ рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рджреЛрдиреЛрдВ, postgresql рдФрд░ sqlite3 рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ:
рдкрд░реАрдХреНрд╖рдг

"""
MyModel objects are created in migration
Test results:
    app/tests.py::test_no_live_server PASSED
    app/tests.py::test_live_server PASSED
    app/tests.py::test_live_server2 FAILED
    app/tests.py::test_no_live_server_after_live_server FAILED
"""

import pytest

from .models import MyModel


@pytest.mark.django_db()
def test_no_live_server():
    """Passed"""
    assert MyModel.objects.count() == 10


@pytest.mark.django_db()
def test_live_server(live_server):
    """Passed"""
    assert MyModel.objects.count() == 10


@pytest.mark.django_db()
def test_live_server2(live_server):
    """Failed, because count() returns 0"""
    assert MyModel.objects.count() == 10


@pytest.mark.django_db()
def test_no_live_server_after_live_server():
    """Failed, because count() returns 0"""
    assert MyModel.objects.count() == 10

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрднреА рднреА рдорд╛рд░рд╛ рдФрд░ рдореБрдЭреЗ рдЗрд╕реЗ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдлреА рд╕рдордп рд▓рдЧрд╛, рднрд▓реЗ рд╣реА рдореИрдВ Django рдХреЗ рдкрд░реАрдХреНрд╖рдг рдврд╛рдВрдЪреЗ рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╕реЗ рдХрд╛рдлреА рдкрд░рд┐рдЪрд┐рдд рд╣реВрдВред

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ Django рдХреЗ TestCase рдПрдХ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рдкреНрд░рджрд░реНрд╢рди рдЯреНрд░реЗрдбрдСрдлрд╝ рд╣реИред рдпрд╣ рдпрд╣рд╛рдБ рдкреНрд░рд▓реЗрдЦрд┐рдд рд╣реИ:
https://docs.djangoproject.com/hi/1.9/topics/testing/overview/#rollback -emulation

рдПрдХ рдирд┐рдпрдорд┐рдд Django рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдореЗрдВ, рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдкрд░ рдПрдХ serialized_rollback = True рд╡рд░реНрдЧ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╕реЗрдЯ рдХрд░рдиреЗ рдореЗрдВ рд╕рдорд╛рдзрд╛рди рд╣реЛрддрд╛ рд╣реИред

рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ pytest-django рдХреА рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреЗрдирд░реЗрдЯ рдХреА рдЧрдИ рдкрд░реАрдХреНрд╖рдг рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╛рди рдкреНрд░рднрд╛рд╡ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред

рд╕рднреА 21 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ transactional_db рд╕реНрдерд┐рд░рддрд╛ live_server рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛ рд░рд╣реА рд╣реИ (рдЗрд╕реЗ @pytest.mark.django_db рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ)ред рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ рдХрдИ рдореБрджреНрджреЗ/рдЪрд░реНрдЪрд╛рдПрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд┐рдЫрд▓реА рдмрд╛рд░ рдЬрдм рдореИрдВрдиреЗ рдЗрд╕реЗ рдХрд░реАрдм рд╕реЗ рджреЗрдЦрд╛, рддреЛ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдХреЛрдИ рдЖрд╕рд╛рди рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рдерд╛ рдЬреЛ рдбреЗрдЯрд╛ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде рдЖрддрд╛ рд╣реИред
рдЕрдкрдиреЗ рдбреЗрдЯрд╛ рдорд╛рдЗрдЧреНрд░реЗрд╢рди/рдбреЗрдЯрд╛ рдлрд┐рдХреНрд╕реНрдЪрд░ рдХреЛ рд▓рдкреЗрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рдЗрдЯреЗрд╕реНрдЯ рдлрд┐рдХреНрд╕реНрдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдПрдХ рд╕рдорд╛рдзрд╛рди рд╣реИред
(рдмреАрдЯреАрдбрдмреНрд▓реНрдпреВ: рд╕рдордп рдХреЗ рд╕рд╛рде рдмрджрд▓рдиреЗ рд╡рд╛рд▓реЗ рдмрд╛рд╣рд░реА рд╕рдВрд╕рд╛рдзрди рдХреА рдмрдЬрд╛рдп рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдмреЗрд╣рддрд░ рддрд░реАрдХреЗ рд╕реЗ рдЗрдирд▓рд╛рдЗрди рдХрд░реЗрдВред)

рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрднреА рднреА рдорд╛рд░рд╛ рдФрд░ рдореБрдЭреЗ рдЗрд╕реЗ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдлреА рд╕рдордп рд▓рдЧрд╛, рднрд▓реЗ рд╣реА рдореИрдВ Django рдХреЗ рдкрд░реАрдХреНрд╖рдг рдврд╛рдВрдЪреЗ рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╕реЗ рдХрд╛рдлреА рдкрд░рд┐рдЪрд┐рдд рд╣реВрдВред

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ Django рдХреЗ TestCase рдПрдХ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рдкреНрд░рджрд░реНрд╢рди рдЯреНрд░реЗрдбрдСрдлрд╝ рд╣реИред рдпрд╣ рдпрд╣рд╛рдБ рдкреНрд░рд▓реЗрдЦрд┐рдд рд╣реИ:
https://docs.djangoproject.com/hi/1.9/topics/testing/overview/#rollback -emulation

рдПрдХ рдирд┐рдпрдорд┐рдд Django рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдореЗрдВ, рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдкрд░ рдПрдХ serialized_rollback = True рд╡рд░реНрдЧ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╕реЗрдЯ рдХрд░рдиреЗ рдореЗрдВ рд╕рдорд╛рдзрд╛рди рд╣реЛрддрд╛ рд╣реИред

рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ pytest-django рдХреА рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреЗрдирд░реЗрдЯ рдХреА рдЧрдИ рдкрд░реАрдХреНрд╖рдг рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╛рди рдкреНрд░рднрд╛рд╡ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░рд┐рд╡рд░реНрддрди рдмрд┐рдирд╛ рд╢рд░реНрдд рдХрдо рд╕реЗ рдХрдо рдХреБрд╢рд▓ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдХреАрдордд рдкрд░ рд╕рдорд╕реНрдпрд╛ рдХреЛ "рд╣рд▓" рдХрд░рддрд╛ рд╣реИред

--- pytest_django/fixtures.py.orig  2016-04-27 17:12:25.000000000 +0200
+++ pytest_django/fixtures.py   2016-04-27 17:21:50.000000000 +0200
@@ -103,6 +103,7 @@

     if django_case:
         case = django_case(methodName='__init__')
+        case.serialized_rollback = True
         case._pre_setup()
         request.addfinalizer(case._post_teardown)

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрдХрдиреАрдХ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рд╕реНрдкрд╖реНрдЯ рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЗрд╕рдХреА рдЕрдиреБрд╢рдВрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ ...

import pytest
from django.core.management import call_command
from pytest_django.fixtures import transactional_db as _transactional_db


def _reload_fixture_data():
    fixture_names = [
        # Create fixtures for the data created by data migrations
        # and list them here.
    ]
    call_command('loaddata', *fixture_names)


@pytest.fixture(scope='function')
def transactional_db(request, _django_db_setup, _django_cursor_wrapper):
    """
    Override a pytest-django fixture to restore the contents of the database.

    This works around https://github.com/pytest-dev/pytest-django/issues/329 by
    restoring data created by data migrations. We know what data matters and we
    maintain it in (Django) fixtures. We don't read it from the database. This
    causes some repetition but keeps this (pytest) fixture (almost) simple.

    """
    try:
        return _transactional_db(request, _django_db_setup, _django_cursor_wrapper)
    finally:
        # /!\ Epically shameful hack /!\ _transactional_db adds two finalizers:
        # _django_cursor_wrapper.disable() and case._post_teardown(). Note that
        # finalizers run in the opposite order of that in which they are added.
        # We want to run after case._post_teardown() which flushes the database
        # but before _django_cursor_wrapper.disable() which prevents further
        # database queries. Hence, open heart surgery in pytest internals...
        finalizers = request._fixturedef._finalizer
        assert len(finalizers) == 2
        assert finalizers[0].__qualname__ == 'CursorManager.disable'
        assert finalizers[1].__qualname__ == 'TransactionTestCase._post_teardown'
        finalizers.insert(1, _reload_fixture_data)

рдХреНрдпрд╛ serialized_rollback рдХреЛ рд╕рд╢рд░реНрдд рд░реВрдк рд╕реЗ рд╕рдХреНрд╖рдо рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдХрд▓реНрдк рдПрдХ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рд╣реЛрдЧрд╛?

рдпрд╛рдиреА рдХреБрдЫ рдРрд╕рд╛

@pytest.mark.django_db(transaction=True, serialized_rollback=True)
def test_foo():
    ...

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред

рдореЗрд░реЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ:

  • transactional_db рд╕реНрдерд┐рд░рддрд╛ live_server рджреНрд╡рд╛рд░рд╛ рдЯреНрд░рд┐рдЧрд░ рдХреА рдЬрд╛рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдХреНрд░рдордмрджреНрдз рд░реЛрд▓рдмреИрдХ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП django_db рд╕реНрдерд┐рд░рддрд╛ рдЬреЛрдбрд╝рдиреЗ рдореЗрдВ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛
  • pytest-django рд╕реЗ рдЕрд╕рдВрдмрдВрдзрд┐рдд - case.serialized_rollback = True рдЕрднреА рднреА рд╡рд┐рдлрд▓ рд░рд╣рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ Django рдПрдХ рдХреНрд░рдо рдореЗрдВ deserialized рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ рдЬреЛ FK рдмрд╛рдзрд╛рдУрдВ рдХрд╛ рд╕рдореНрдорд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ Django рдореЗрдВ рдПрдХ рдмрдЧ рд╣реИ

рдмрд┐рд▓реНрдХреБрд▓ рдареАрдХ рд╣реИ :)

рдореЗрд░реЗ рдкрд╛рд╕ рдЕрднреА рдареАрдХ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди django_db рдорд╛рд░реНрдХрд░ рдореЗрдВ рдРрд╕рд╛ рд╡рд┐рдХрд▓реНрдк рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ case.serialized_rollback = True (рдЬреИрд╕реЗ рдЖрдкрдиреЗ рдКрдкрд░ рдХрд┐рдпрд╛) рдХреЛ рд╕реЗрдЯ рдХрд░рдирд╛ рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕рд░рд▓ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореИрдВрдиреЗ рдКрдкрд░ рдмрддрд╛рдП рдЧрдП Django рдмрдЧ рдХреЗ рд▓рд┐рдП рдЯрд┐рдХрдЯ: https://code.djangoproject.com/ticket/26552

@pelme - рдХреНрдпрд╛ рдпрд╣ рдкреБрд▓ рдЕрдиреБрд░реЛрдз "рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕реАрдзрд╛" рджреГрд╖реНрдЯрд┐рдХреЛрдг рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдХрд▓реНрдкрдирд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ?

рдЬрдирд╕рдВрдкрд░реНрдХ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд-рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рджред рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕рд╣реА рджрд┐рдЦрддрд╛ рд╣реИ рдФрд░ рдЬреЛ рдореИрдВрдиреЗ рдХрд▓реНрдкрдирд╛ рдХреА рдереАред рдореИрдВрдиреЗ рдПрдХ serialized_rollback рд╕реНрдерд┐рд░рддрд╛ рд░рдЦрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╕реЛрдЪрд╛ рдерд╛ рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдЕрдиреНрдп рдлрд┐рдХреНрд╕реНрдЪрд░ рд╕реЗ рдордЬрдмреВрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реИред

рд╣рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рднреА рдПрдХ рдкрд░реАрдХреНрд╖рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕рд╣реА рджрд┐рдЦрддрд╛ рд╣реИ!

рдореИрдВ рдкреИрдЪ рдХреЛ рдкреЙрд▓рд┐рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордп рдирд┐рдХрд╛рд▓рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ (рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрднреА рддрдХ рдЪрд▓рд╛рдпрд╛ рднреА рдирд╣реАрдВ рд╣реИ)ред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рдореИрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреВрдВ, рдореБрдЭреЗ Django рдореЗрдВ рдЙрдкрд░реЛрдХреНрдд рдмрдЧ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

pytest-django 3.0 рдХреЗ рд▓рд┐рдП рдЙрдкрд░реЛрдХреНрдд рд╣реИрдХ рдХрд╛ рдЕрджреНрдпрддрди рд╕рдВрд╕реНрдХрд░рдг:

@pytest.fixture(scope='function')
def transactional_db(request, django_db_setup, django_db_blocker):
    """
    Override a pytest-django fixture to restore the contents of the database.

    This works around https://github.com/pytest-dev/pytest-django/issues/329 by
    restoring data created by data migrations. We know what data matters and we
    maintain it in (Django) fixtures. We don't read it from the database. This
    causes some repetition but keeps this (pytest) fixture (almost) simple.

    """
    try:
        return _transactional_db(request, django_db_setup, django_db_blocker)
    finally:
        # /!\ Epically shameful hack /!\ _transactional_db adds two finalizers:
        # django_db_blocker.restore() and test_case._post_teardown(). Note that
        # finalizers run in the opposite order of that in which they are added.
        # We want to run after test_case._post_teardown() flushes the database
        # but before django_db_blocker.restore() prevents further database
        # queries. Hence, open heart surgery in pytest internals...
        finalizers = request._fixturedef._finalizer
        assert len(finalizers) == 2
        assert finalizers[0].__qualname__ == '_DatabaseBlocker.restore'
        assert finalizers[1].__qualname__ == 'TransactionTestCase._post_teardown'
        finalizers.insert(1, _reload_fixture_data)

рдЕрджреНрдпрддрди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж рдФрд░ рдЦреЗрдж рд╣реИ рдХрд┐ рдореИрдВ рдЗрд╕реЗ 3.0 рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ред рдореИрдВ рдЕрдЧрд▓реА рд░рд┐рд▓реАрдЬ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдкрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛!

рдХреНрдпрд╛ рдЗрд╕реЗ рдЕрдЧрд▓реА рд░рд┐рд▓реАрдЬ рдореЗрдВ рджреЗрдЦрдиреЗ рдХрд╛ рдХреЛрдИ рдореМрдХрд╛ рд╣реИ?

рдзрдиреНрдпрд╡рд╛рдж

@ рд╡рд┐рдПрд░рд╛рдЯ
рд╣рд╛рдВ рд╢рд╛рдпрджред

рддреЛ рдХреГрдкрдпрд╛ рдЙрд╕рд╕реЗ рдкрд╣рд▓реЗ

рд╣рд╛рдп рджреЛрд╕реНрддреЛрдВ,
рдЗрд╕рдХреА рддрд╛рдЬрд╛ рд╕реНрдерд┐рддрд┐ рдХреНрдпрд╛ рд╣реИ? рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдореИрдВ Django рд╕реЗ StaticLiveServerTestCase рдХреНрд▓рд╛рд╕ рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ рдЯреЗрд╕реНрдЯ рд░рдирд░ рдХреЗ рд░реВрдк рдореЗрдВ pytest рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдореИрдВрдиреЗ рд╡рд░реНрдЧ рд╡рд┐рд╢реЗрд╖рддрд╛ serialized_rollback = True рд╕реЗрдЯ рдХреА рд╣реИ рд▓реЗрдХрд┐рди рдпрд╣ рдЕрдиреБрдХреНрд░рдо рд╕реЗ рдкрд╣рд▓реЗ рдкрд░реАрдХреНрд╖рдг рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╕рдордп рд╣реА рдкреНрд░рднрд╛рд╡реА рд╣реЛрддрд╛ рд╣реИред

рдмрд╕ рдЗрд╕реА рдХреА рдЪрдкреЗрдЯ рдореЗрдВ рдЖ рдЧрдпрд╛ред рдЪрд╛рд░реЛрдВ рдУрд░ рджреЗрдЦрдиреЗ рдкрд░ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдХреБрдЫ рдЬрдирд╕рдВрдкрд░реНрдХ рд╣реБрдП рд╣реИрдВ рд▓реЗрдХрд┐рди рдЙрдирдореЗрдВ рд╕реЗ рдХреЛрдИ рднреА рд╡рд┐рд▓рдп рдирд╣реАрдВ рд╣реБрдЖ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред
рдХреНрдпрд╛ рдХреЛрдИ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдпрд╣ рдореБрджреНрджрд╛ рдЦреБрд▓рд╛ рд░рд╣рддрд╛ рд╣реИ?

рдХреБрдЫ рдкреАрдЖрд░

рд╕рдВрднрд╛рд╡рдирд╛/рдХреЗрд╡рд▓ https://github.com/pytest-dev/pytest-django/issues/329 , рдирд╣реАрдВ?

рдкрд┐рдЫрд▓реА рдмрд╛рд░ рдореИрдВрдиреЗ рдХрд┐рд╕реА рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдорджрдж рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкреВрдЫрд╛ рдерд╛, рдФрд░ рдЗрд╕рдореЗрдВ рдХрдИ рд╡рд┐рд░реЛрдз рд╣реИрдВ (рд╢рд╛рдпрдж рдХреЗрд╡рд▓ рдХрд╛рд▓реЗ рд░рдВрдЧ рдХреЗ рдХрд╛рд░рдг)ред

рдореИрдВ рдЕрдм рднреА рдЗрд╕рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд┐рд╕реА рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд▓рд┐рдП рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВ - рдореИрдВ рд╕реНрд╡рдпрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рддреНрд╡рд░рд┐рдд рдЙрддреНрддрд░ @blueyed рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред
pytest / pytest-django рдХрд╛ рдореЗрд░рд╛ рдЬреНрдЮрд╛рди рдиреНрдпреВрдирддрдо рд╣реИ рд▓реЗрдХрд┐рди рдореИрдВ рдЗрд╕реЗ рдЕрдкрдиреЗ рдХрд┐рд╕реА рджрд┐рди/рд╢рд╛рдпрдж рд╕реВрдЪреА рдореЗрдВ рд░рдЦреВрдВрдЧрд╛! :рдбреА

pytest 5.2.1, pytest-django 3.5.1 рдХреЗ рд▓рд┐рдП рдЙрдкрд░реЛрдХреНрдд рд╣реИрдХ рдХрд╛ рдЕрджреНрдпрддрди рд╕рдВрд╕реНрдХрд░рдг:

from functools import partial

@pytest.fixture
def transactional_db(request, transactional_db, django_db_blocker):
    # Restore DB content after all of transactional_db's finalizers have
    # run. Finalizers are run in the opposite order of that in which they
    # are added, so we prepend the restore to the front of the list.
    #
    # Works for pytest 5.2.1, pytest-django 3.5.1
    restore = partial(_restore_db_content, django_db_blocker)
    finalizers = request._fixture_defs['transactional_db']._finalizers
    finalizers.insert(0, restore)

    # Simply restoring after yielding transactional_db wouldn't work because
    # it would run before transactional_db's finalizers which contains the truncate.
    return transactional_db

def _restore_db_content(django_db_fixture, django_db_blocker):
    with django_db_blocker.unblock():
        call_command('loaddata', '--verbosity', '0', 'TODO your fixture')

рдореБрдЭреЗ рдореВрд▓ transactional_db рд╕реНрдерд┐рд░рддрд╛ рдкрд░ рдирд┐рд░реНрднрд░ рд░рд╣рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдЗрд╕реЗ рдкрд╛рдЗрд╕реНрдЯреЗрд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рд╕реАрдзреЗ рдлрд┐рдХреНрд╕реНрдЪрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдореИрдВ рддрдм рдореВрд▓ рд╕реНрдерд┐рд░рддрд╛ рдХреА рд╕реНрдерд┐рд░рддрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕реЗ рдЕрдВрддрд┐рдо рд░реВрдк рджреЗрддрд╛ рд╣реВрдВред рдЗрдВрдбреЗрдХреНрд╕ 1 рдкрд░ рдбрд╛рд▓рдиреЗ рдХреЗ рджреМрд░рд╛рди рдЕрднреА рднреА рдХрд╛рдо рдХрд┐рдпрд╛ рд╣реИ, рдореИрдВ рд╕рднреА рдлрд╛рдЗрдирд▓рд╛рдЗрдЬрд╝рд░ рд╕реЗ рдкрд╣рд▓реЗ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдкреБрдирд░реНрд╕реНрдерд╛рдкрдирд╛ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ django_db_blocker рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдереЛрдбрд╝рд╛ рдХрдо рдирд╛рдЬреБрдХ рд▓рдЧрддрд╛ рд╣реИред

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдЕрдВрдд рдореЗрдВ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдкреНрд░рдпрд╛рд╕ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЧрдпрд╛ред

@lukaszb

https://github.com/pytest-dev/pytest-django/issues/848

рдореИрдВ pytest-django рдХреЗ рдЗрд╕ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ (https://github.com/pytest-dev/pytest-django/pull/721/files),
рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рддреНрд░реБрдЯрд┐ред

image

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

asfaltboy picture asfaltboy  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

AndreaCrotti picture AndreaCrotti  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

mpasternak picture mpasternak  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jedie picture jedie  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

WoLpH picture WoLpH  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ