Pytest-django: pytest.mark.django_db плохо работает с setup_module ()

Созданный на 14 сент. 2013  ·  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() не запускается (я пытался вызвать там исключение)

Извините, это должно быть usefixtures, а не usefixture:

http://pytest.org/latest/fixture.html#usefixtures

Теперь я получаю 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, но вместо этого он терпит неудачу в тесте, потому что транзакция откатывается после первого теста, следовательно, откат тестовой таблицы.)

Я пытаюсь протестировать пару утилит низкого уровня db, которые используют курсор django внутри - https://github.com/Suor/handy/blob/master/handy/db.py#L40

И я считаю, что будет гораздо сложнее определить модель в models.py а затем использовать фикстуры в каком-нибудь формате django, чтобы проверить это. Всего будет 3 файла для проверки довольно простой функциональности.

Я просто хочу выполнить некоторый код инициализации перед запуском тестов, чтобы у меня были данные для игры.

О, я заставил это работать! Помогло обертывание инициализации SQL в begin; ... commit; .

Большое спасибо за все советы, которые вы дали.

Это хакерство, которое мне кажется немного хрупким. Я бы, вероятно, установил дополнительное приложение, которое используется только для тестов с простой моделью, которую вы затем можете использовать для запуска этих функций. Затем вы можете легко использовать ORM Django для заполнения данных в ваших тестах. Это немного больше набора текста и пара дополнительных файлов, но тогда это должно быть безопасно для будущих поломок.

Если кто-то еще обнаружит эту проблему: выполнение настройки базы данных в setup_function / setup_class / setup_module на самом деле не поддерживается или возможно каким-либо образом, поскольку настройка базы данных pytest-django основана на фикстурах.

Решение состоит в том, чтобы использовать приспособление, которое правильно запрашивает приспособление db:
http://pytest-django.readthedocs.org/en/latest/helpers.html#db

@pelme
С помощью прибора 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 в том виде, в котором оно реализовано в настоящее время. В PR # 258 была проделана некоторая работа, чтобы сделать возможным создание состояния базы данных, связанного с областью действия класса / модуля / сеанса.

Даже несмотря на то, что эта проблема довольно старая, я счел полезным найти решение проблемы, с которой я столкнулся с pytest и pytest-django . Поскольку pytest 3.5.0 возникает проблема при использовании django_db mark и module level.

Ниже работал до 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 рейтинги

Смежные вопросы

tolomea picture tolomea  ·  4Комментарии

rlskoeser picture rlskoeser  ·  7Комментарии

jedie picture jedie  ·  7Комментарии

MRigal picture MRigal  ·  3Комментарии

koxu1996 picture koxu1996  ·  3Комментарии