Pytest-django: ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” live_server ๊ณ ์ • ์žฅ์น˜๋ฅผ ์‚ฌ์šฉํ•œ ํ…Œ์ŠคํŠธ

์— ๋งŒ๋“  2016๋…„ 04์›” 14์ผ  ยท  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/en/1.9/topics/testing/overview/#rollback -emulation

์ผ๋ฐ˜ Django ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์—์„œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— serialized_rollback = True ํด๋ž˜์Šค ์†์„ฑ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

pytest-django์˜ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋กœ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  21 ๋Œ“๊ธ€

transactional_db ๊ณ ์ • ์žฅ์น˜๊ฐ€ live_server ์˜ํ•ด ์ž๋™์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค( @pytest.mark.django_db ๋กœ ํ‘œ์‹œํ•  ํ•„์š”๊ฐ€ ์—†์Œ). ์ด์™€ ๊ด€๋ จํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ/ํ† ๋ก ์ด ์žˆ์ง€๋งŒ ์ง€๋‚œ๋ฒˆ์— ์ž์„ธํžˆ ์‚ดํŽด๋ณด์•˜์„ ๋•Œ ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐœ์ƒํ•˜๋Š” ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์‰ฌ์šด ํ•ด๊ฒฐ์ฑ…์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ pytest ๊ณ ์ • ์žฅ์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜/๋ฐ์ดํ„ฐ ๊ณ ์ • ์žฅ์น˜๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
(btw: ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ์™ธ๋ถ€ ๋ฆฌ์†Œ์Šค๋ณด๋‹ค ๋ฌธ์ œ์— ํ…Œ์ŠคํŠธ๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๋„ฃ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.)

๋‚˜๋„ ๋ฐฉ๊ธˆ ์ด๊ฒƒ์„ ์ณค๊ณ  Django์˜ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์— ์ƒ๋‹นํžˆ ์ต์ˆ™ํ•˜์ง€๋งŒ ์ถ”์ ํ•˜๋Š” ๋ฐ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ Django์˜ TestCase ์˜ ๋†€๋ผ์šด ์„ฑ๋Šฅ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
https://docs.djangoproject.com/en/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์™€ ๊ด€๋ จ ์—†์Œ -- Django๊ฐ€ FK ์ œ์•ฝ ์กฐ๊ฑด์„ ์กด์ค‘ํ•˜์ง€ ์•Š๋Š” ์ˆœ์„œ๋กœ ์—ญ์ง๋ ฌํ™”๋œ ๊ฐ์ฒด๋ฅผ ์‹œ๋„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— case.serialized_rollback = True ์—ฌ์ „ํžˆ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. Django์˜ ๋ฒ„๊ทธ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ข‹์•„, ์™„๋ฒฝํ•ด :)

์ง€๊ธˆ์€ ์ˆ˜์ •ํ•  ์‹œ๊ฐ„์ด ์—†์ง€๋งŒ django_db ๋งˆ์ปค์— ์ด๋Ÿฌํ•œ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๊ณ  case.serialized_rollback = True (์œ„์—์„œ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ)์€ ๋น„๊ต์  ๊ฐ„๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ Django ๋ฒ„๊ทธ ํ‹ฐ์ผ“: https://code.djangoproject.com/ticket/26552

@pelme -- ์ด ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๊ฐ€ ๋‹น์‹ ์ด ๊ตฌ์ƒํ•˜๊ณ  ์žˆ๋Š” "์ƒ๋Œ€์ ์œผ๋กœ ๊ฐ„๋‹จํ•œ" ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๊นŒ?

PR ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„์ด ์ •ํ™•ํ•˜๊ณ  ๋‚ด๊ฐ€ ์ƒ์ƒํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” 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์— ์ ์šฉํ•˜์ง€ ๋ชปํ•ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค๋ฅผ ์œ„ํ•ด ์ด๊ฒƒ์„ ์–ป์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

๋‹ค์Œ ๋ฆด๋ฆฌ์Šค์—์„œ ๋ณผ ๊ธฐํšŒ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ฐ์‚ฌ ํ•ด์š”

@Wierrat
๋„ค ์•„๋งˆ๋„.

๊ทธ ์ „์— https://github.com/pytest-dev/pytest-django/pull/353์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋„์™€์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…• ์—ฌ๋Ÿฌ๋ถ„,
์ด๊ฒƒ์˜ ์ตœ์‹  ์ƒํƒœ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ํŠนํžˆ Django์˜ StaticLiveServerTestCase ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ๋กœ pytest๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์†์„ฑ serialized_rollback = True ํ–ˆ์ง€๋งŒ ์‹œํ€€์Šค์—์„œ ์ฒซ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋งŒ ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋†ˆ์—๊ฒŒ ๋ง‰ ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ์ฃผ์œ„๋ฅผ ๋‘˜๋Ÿฌ๋ณด๋ฉด ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ PR์ด ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™์ง€๋งŒ ๊ทธ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๋ณ‘ํ•ฉ๋˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ๊ฐ€ ๊ณ„์† ์—ด๋ ค ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ผ๋ถ€ ํ™๋ณด

https://github.com/pytest-dev/pytest-django/issues/329 , ์•„๋‹ˆ์š”?

๋งˆ์ง€๋ง‰์œผ๋กœ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•œ ๋„์›€์„ ์š”์ฒญํ–ˆ๋Š”๋ฐ ๋ช‡ ๊ฐ€์ง€ ์ถฉ๋Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค(๊ฒ€์ •์ƒ‰ ๋•Œ๋ฌธ์ผ ์ˆ˜๋„ ์žˆ์Œ).

๋‚˜๋Š” ์—ฌ์ „ํžˆ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋„์›€์„ ์ค„ ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@blueyed ๋น ๋ฅธ ๋‹ต๋ณ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
pytest / pytest-django์— ๋Œ€ํ•œ ๋‚˜์˜ ์ง€์‹์€ ๋ฏธ๋ฏธํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์„ ๋‚ด ์–ธ์  ๊ฐ€/์•„๋งˆ๋„ ๋ชฉ๋ก์— ๋„ฃ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค! :NS

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')

pytest๊ฐ€ ๋” ์ด์ƒ ๊ณ ์ • ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹  ์›๋ž˜ transactional_db ๊ณ ์ • ์žฅ์น˜์— ์˜์กดํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์›๋ž˜ ์กฐ๋ช…๊ธฐ์˜ ์กฐ๋ช…๊ธฐ def๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ข…๋ฃŒ์ž๋ฅผ ์•ž์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค 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 ๋“ฑ๊ธ‰

๊ด€๋ จ ๋ฌธ์ œ

tolomea picture tolomea  ยท  4์ฝ”๋ฉ˜ํŠธ

ryankask picture ryankask  ยท  5์ฝ”๋ฉ˜ํŠธ

rodrigorodriguescosta picture rodrigorodriguescosta  ยท  4์ฝ”๋ฉ˜ํŠธ

mjk4 picture mjk4  ยท  4์ฝ”๋ฉ˜ํŠธ

rlskoeser picture rlskoeser  ยท  7์ฝ”๋ฉ˜ํŠธ