Pytest-django: pytest.mark.django_dbλŠ” setup_module()κ³Ό 잘 μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

에 λ§Œλ“  2013λ…„ 09μ›” 14일  Β·  15μ½”λ©˜νŠΈ  Β·  좜처: pytest-dev/pytest-django

λ‚΄ ν…ŒμŠ€νŠΈ μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

import pytest
pytestmark = pytest.mark.django_db

from handy.db import do_sql, fetch_val

def setup_module(fetch_val):
    print 1
    do_sql('''
        create table test (
            id int primary key,
            tag int not null
        );

        insert into test values (1, 10), (2, 20);
    ''')
    print 2

def test_fetch_val():
    print 3
    assert fetch_val('select min(id) from test') == 1

그리고 DatabaseError: relation "test" does not exist μ—μ„œ test_fetch_val() λ°›μŠ΅λ‹ˆλ‹€. λ‚˜λŠ” λ˜ν•œ μ–»λŠ”λ‹€

2
Creating test database for alias 'default'...
3

캑처된 좜λ ₯. λ°μ΄ν„°λ² μ΄μŠ€κ°€ μƒμ„±λ˜κΈ° 전에 setup_module() κ°€ 호좜된 것 κ°™μŠ΅λ‹ˆλ‹€.

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

+1 μ €μ—κ²ŒλŠ” 일뢀 초기 Djano λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ μ „ν™˜ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλ„ API ν…ŒμŠ€νŠΈ 사둀에 λŒ€ν•œ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•  λ•Œ μ£Όμš” λ‹¨μ μž…λ‹ˆλ‹€. μ‹€μ œλ‘œ μ§€μ›ν•˜λŠ” μ„Έμ…˜/λͺ¨λ“ˆ λ°μ΄ν„°λ² μ΄μŠ€ κ³ μ • μž₯μΉ˜λŠ” κΈ°λ³Έ κΈ°λŠ₯이어야 ν•©λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법에 λŒ€ν•œ μ œμ•ˆ 사항이 μžˆμŠ΅λ‹ˆκΉŒ?

λͺ¨λ“  15 λŒ“κΈ€

django_db λ§ˆν¬λŠ” ν”½μŠ€μ²˜λ₯Ό 기반으둜 ν•˜λŠ”λ°, ν”½μŠ€μ²˜μ™€ setup_* λ©”μ†Œλ“œ 사이에 μ–΄λ–»κ²Œ 톡신해야 ν•˜λŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

λ™μΌν•œ 것을 λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ λŒ€μ‹  λͺ¨λ“ˆ λ²”μœ„ κ³ μ • μž₯치λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? 즉, λ­”κ°€

pytestmark = pytest.mark.usefixture('test_table')

@pytest.fixture(scope='module')
def test_table(db):
    do_sql('create table ...')

def test_fetch_val():
    assert fetch_val('...') == 1

방금 μ‹œλ„ν–ˆμŠ΅λ‹ˆλ‹€. μž‘λ™ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ§€κΈˆ Database access not allowed, use the "django_db" mark to enable λ°›μŠ΅λ‹ˆλ‹€.
λ˜ν•œ test_table() κ°€ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€(μ—¬κΈ°μ„œ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚€λ €κ³  ν–ˆμŠ΅λ‹ˆλ‹€)

μ£„μ†‘ν•©λ‹ˆλ‹€. Fixtureκ°€ μ•„λ‹ˆλΌ Fixtureλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

http://pytest.org/latest/fixture.html#useν”½μŠ€μ²˜

이제 ScopeMismatchError: You tried to access the 'function' scoped funcarg 'db' with a 'module' scoped request object, involved factories μ–»μŠ΅λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜μ—μ„œ db λ§€κ°œλ³€μˆ˜λ₯Ό μ œκ±°ν•˜λ©΄ κ³ μ • μž₯μΉ˜κ°€ μ‹€νŒ¨ν•˜κ³  scope='module'을 μ œκ±°ν•˜λ©΄ μž‘λ™ν•œλ‹€κ³  μƒκ°ν•˜μ§€λ§Œ λͺ¨λ“  ν…ŒμŠ€νŠΈμ— λŒ€ν•΄ test_table() κ°€ μ‹€ν–‰λ˜λ―€λ‘œ μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” λ˜ν•œ μ‹œλ„ν–ˆλ‹€

pytestmark = pytest.mark.django_db

@pytest.fixture(scope='module')
def test_table():
    do_sql('''
        create table test (
            id int primary key,
            tag int not null
        );

        insert into test values (1, 10), (2, 20);
    ''')

def test_fetch_val(test_table):
    assert fetch_val('select min(id) from test') == 1

def test_fetch_val2(test_table):
    assert fetch_val('select min(id) from test') == 1

거의 μž‘λ™ν•˜μ§€λ§Œ 두 번째 ν…ŒμŠ€νŠΈλŠ” DatabaseError: relation "test" does not exist μ–΄λ–»κ²Œλ“  μ‹€νŒ¨ν•©λ‹ˆλ‹€. λ‚˜μ—κ²Œ μ™„μ „ν•œ λ―ΈμŠ€ν„°λ¦¬.

Django와 django_db λ§ˆμ»€λŠ” 각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ 자체 νŠΈλžœμž­μ…˜μ—μ„œ μ‹€ν–‰λ˜λŠ” λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜λ―€λ‘œ λ°μ΄ν„°λ² μ΄μŠ€μ— 데이터λ₯Ό μ‚½μž…ν•˜λŠ” λͺ¨λ“ˆ μˆ˜μ€€ κ³ μ • μž₯μΉ˜μ™€ ν•¨κ»˜ django_dbλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 μ‹€μ œλ‘œ μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ‚¬μš© μ‚¬λ‘€λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? Djangoκ°€ μ•„λ‹Œ ν…ŒμŠ€νŠΈμ—μ„œ "μ†μœΌλ‘œ" λ°μ΄ν„°λ² μ΄μŠ€ ν…Œμ΄λΈ”μ„ λ§Œλ“œλŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? ν•˜μ§€λ§Œ μ—¬μ „νžˆ Django의 ν…ŒμŠ€νŠΈ λ°μ΄ν„°λ² μ΄μŠ€/ν…ŒμŠ€νŠΈ λ°μ΄ν„°λ² μ΄μŠ€ μ»€μ„œλ₯Ό μ‚¬μš©ν•˜κ³  μ‹ΆμŠ΅λ‹ˆκΉŒ?

일반 λ°μ΄ν„°λ² μ΄μŠ€ μ»€μ„œλ₯Ό κ΅¬μ„±ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” μ›ν•˜λŠ” 것을 얻을 수 μ—†μŠ΅λ‹ˆκΉŒ?

(λ§ˆμ§€λ§‰ μ˜ˆμ œλŠ” ScopeMismatchErrorλ₯Ό ν”Όν•˜μ§€λ§Œ 첫 번째 ν…ŒμŠ€νŠΈ 후에 νŠΈλžœμž­μ…˜μ΄ λ‘€λ°±λ˜μ–΄ ν…ŒμŠ€νŠΈ ν…Œμ΄λΈ”μ„ λ‘€λ°±ν•˜κΈ° λ•Œλ¬Έμ— λŒ€μ‹  ν…ŒμŠ€νŠΈμ—μ„œ μ‹€νŒ¨ν•©λ‹ˆλ‹€.)

λ‚΄λΆ€μ μœΌλ‘œ django μ»€μ„œλ₯Ό μ‚¬μš©ν•˜λŠ” λͺ‡ 가지 μ €μˆ˜μ€€ db μœ ν‹Έλ¦¬ν‹°λ₯Ό ν…ŒμŠ€νŠΈν•˜λ €κ³  ν•©λ‹ˆλ‹€. - https://github.com/Suor/handy/blob/master/handy/db.py#L40

그리고 models.py 둜 λͺ¨λΈμ„ μ •μ˜ν•œ λ‹€μŒ 이λ₯Ό ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ 일뢀 django ν˜•μ‹μ˜ κ³ μ • μž₯치λ₯Ό μ •μ˜ν•˜λŠ” 것이 훨씬 더 λ³΅μž‘ν•  κ²ƒμž…λ‹ˆλ‹€. κ½€ 기본적인 κΈ°λŠ₯을 ν…ŒμŠ€νŠΈν•˜λ €λ©΄ 총 3개의 파일이 ν•„μš”ν•©λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•˜κΈ° 전에 λͺ‡ 가지 데이터λ₯Ό 가지고 놀 수 μžˆλ„λ‘ μ΄ˆκΈ°ν™” μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

였, ν•΄λƒˆμ–΄! μ΄ˆκΈ°ν™” SQL을 begin; ... commit; 둜 λž˜ν•‘ν•˜λŠ” 것이 도움이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μ œκ³΅ν•œ λͺ¨λ“  νŒμ— κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

그것은 λ‚˜μ—κ²Œ μ•½κ°„ μ·¨μ•½ν•΄ λ³΄μ΄λŠ” ν•΄ν‚Ήμž…λ‹ˆλ‹€. λ‚˜λŠ” μ•„λ§ˆλ„ 당신이 κ·Έ κΈ°λŠ₯을 μ‹€ν–‰ν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆλŠ” κ°„λ‹¨ν•œ λͺ¨λΈμ΄ μžˆλŠ” ν…ŒμŠ€νŠΈμ—λ§Œ μ‚¬μš©λ˜λŠ” μΆ”κ°€ 앱을 μ„€μ •ν•  κ²ƒμž…λ‹ˆλ‹€. 그런 λ‹€μŒ Django의 ORM을 μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈμ˜ 데이터λ₯Ό μ‰½κ²Œ μ±„μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. μ•½κ°„ 더 λ§Žμ€ μž…λ ₯κ³Ό λͺ‡ 개의 μΆ”κ°€ 파일이 ν•„μš”ν•˜μ§€λ§Œ λ‚˜μ€‘μ— νŒŒμ†λ  경우 μ•ˆμ „ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ‹€λ₯Έ μ‚¬λžŒμ΄ 이 문제λ₯Ό λ°œκ²¬ν•˜λ©΄: pytest-django의 λ°μ΄ν„°λ² μ΄μŠ€ 섀정이 κ³ μ • μž₯치λ₯Ό 기반으둜 ν•˜κΈ° λ•Œλ¬Έμ— setup_function/setup_class/setup_moduleμ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€ 섀정을 μˆ˜ν–‰ν•˜λŠ” 것은 μ‹€μ œλ‘œ μ§€μ›λ˜μ§€ μ•Šκ±°λ‚˜ 쒋은 λ°©μ‹μœΌλ‘œ κ°€λŠ₯ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

해결책은 db κ³ μ • μž₯치λ₯Ό μ μ ˆν•˜κ²Œ μš”μ²­ν•˜λŠ” κ³ μ • μž₯치λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
http://pytest-django.readthedocs.org/en/latest/helpers.html#db

@νŽ λ©”
db κ³ μ • μž₯치λ₯Ό μ‚¬μš©ν•˜λ©΄ 클래슀, λͺ¨λ“ˆ λ˜λŠ” μ„Έμ…˜μ΄ μ•„λ‹Œ ν•¨μˆ˜ λ²”μœ„μ—μ„œλ§Œ μ΄λŸ¬ν•œ 섀정을 μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ 클래슀 ν…ŒμŠ€νŠΈκ°€ μ‹€ν–‰λ˜κΈ° 전에 일뢀 λ ˆμ½”λ“œλ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— μ±„μ›Œμ•Ό ν•˜λŠ” κ²½μš°μž…λ‹ˆλ‹€.

==================================== ERRORS ====================================
___________ ERROR at setup of TestHistoryAlerts.test_one_point_data ____________
ScopeMismatch: You tried to access the 'function' scoped fixture 'db' with a 'session' scoped request object, involved factories
tests/conftest.py:140:  def ts(db)
../../../../.virtualenvs/app/lib/python2.7/site-packages/pytest_django/fixtures.py:158:  def db(request, _django_db_setup, _django_cursor_wrapper)

μ²˜λ¦¬ν•  수 μžˆλŠ” λ‹€λ₯Έ 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

λ„€, ν˜„μž¬ κ΅¬ν˜„λ˜μ–΄ μžˆλŠ” db Fixture의 ν•œκ³„μž…λ‹ˆλ‹€. PR #258μ—λŠ” 클래슀/λͺ¨λ“ˆ/μ„Έμ…˜ λ²”μœ„μ— μ˜ν•΄ 묢인 λ°μ΄ν„°λ² μ΄μŠ€ μƒνƒœλ₯Ό 생성할 수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•œ μž‘μ—…μ΄ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

μ–΄λ €μš΄ 이 λ¬Έμ œλŠ” κ½€ μ˜€λž˜λ˜μ—ˆμ§€λ§Œ pytest 및 pytest-django λ¬Έμ œμ— λŒ€ν•œ 해결책을 μ°ΎλŠ” 것이 μœ μš©ν•˜λ‹€λŠ” 것을 μ•Œμ•˜μŠ΅λ‹ˆλ‹€. pytest 3.5.0 이후 django_db λ§ˆν¬μ™€ module 레벨 λΉ„ν’ˆμ„ μ‚¬μš©ν•  λ•Œ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

μ•„λž˜λŠ” 3.5.0 이전에 μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€(적어도 문제λ₯Ό μΌμœΌν‚€μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€).

@pytest.fixture(scope='module')
def user():
    return User.objects.create(...)

@pytest.mark.django_db
def test_some_case(user):
    pass

3.5.0 μ—λŠ”

Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

해결책은 scope='module' λ₯Ό μ œκ±°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

+1 μ €μ—κ²ŒλŠ” 일뢀 초기 Djano λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ μ „ν™˜ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλ„ API ν…ŒμŠ€νŠΈ 사둀에 λŒ€ν•œ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•  λ•Œ μ£Όμš” λ‹¨μ μž…λ‹ˆλ‹€. μ‹€μ œλ‘œ μ§€μ›ν•˜λŠ” μ„Έμ…˜/λͺ¨λ“ˆ λ°μ΄ν„°λ² μ΄μŠ€ κ³ μ • μž₯μΉ˜λŠ” κΈ°λ³Έ κΈ°λŠ₯이어야 ν•©λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법에 λŒ€ν•œ μ œμ•ˆ 사항이 μžˆμŠ΅λ‹ˆκΉŒ?

+1

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰