Pytest-django: pytest.mark.django_db no funciona bien con setup_module ()

Creado en 14 sept. 2013  ·  15Comentarios  ·  Fuente: pytest-dev/pytest-django

Aquí está mi código de prueba:

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

Y obtengo DatabaseError: relation "test" does not exist de test_fetch_val() . Yo tambien consigo

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

salida capturada. Parece que se llama a setup_module() antes de crear la base de datos.

Comentario más útil

+1 Para mí, simplemente cambiar de algunas pruebas unitarias iniciales de Djano, este es un gran inconveniente, al inicializar la base de datos para mis casos de prueba de API. En realidad, el soporte de accesorios de base de datos de sesiones / módulos debería ser una característica básica. ¿Alguna sugerencia de cómo resolver esto?

Todos 15 comentarios

La marca django_db se basa en dispositivos, no estoy seguro de cómo comunicarme entre dispositivos y los métodos setup_ *.

¿Podrías usar un dispositivo con ámbito de módulo en su lugar para lograr lo mismo? Es decir, algo como

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

Acabo de tratar. No funcionó. Ahora obtengo Database access not allowed, use the "django_db" mark to enable .
Además, test_table() no se ejecuta (intenté generar una excepción allí)

Lo siento, deberían ser accesorios de uso, no accesorios de uso:

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

Ahora obtengo ScopeMismatchError: You tried to access the 'function' scoped funcarg 'db' with a 'module' scoped request object, involved factories .

Eliminar el parámetro db del parámetro da como resultado una falla del dispositivo, eliminar el alcance = 'módulo' hace que las ideas funcionen, pero luego test_table() se ejecuta para cada prueba, lo cual no quiero.

Yo tambien probé

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

que casi funciona, pero la segunda prueba falla de alguna manera con DatabaseError: relation "test" does not exist . Un completo misterio para mí.

Django y el marcador django_db funcionan de la misma manera que cada caso de prueba se ejecuta en su propia transacción, por lo tanto, usar django_db con un dispositivo de nivel de módulo que inserta datos en la base de datos no tiene sentido.

¿Cuál es su caso de uso aquí? ¿Cómo es que está creando una tabla de base de datos "a mano" en sus pruebas, y no con Django, pero aún desea usar la base de datos de prueba / el cursor de la base de datos de prueba de Django?

¿No podría lograr lo que busca simplemente construyendo un cursor de base de datos simple?

(El último ejemplo evita el ScopeMismatchError, pero falla en la prueba porque la transacción se revierte después de la primera prueba, por lo tanto, revierte la tabla de prueba).

Estoy tratando de probar un par de utilidades de base de datos de bajo nivel, que usan el cursor django internamente: https://github.com/Suor/handy/blob/master/handy/db.py#L40

Y creo que será mucho más complicado definir un modelo en models.py y luego accesorios en algún formato de django para probar eso. Serían 3 archivos en total para probar una funcionalidad bastante básica.

Solo quiero ejecutar un código de inicialización antes de ejecutar las pruebas para tener algunos datos con los que jugar.

¡Oh, lo hice funcionar! Envolver el SQL de inicialización en begin; ... commit; ayudó.

Muchas gracias por todos los consejos que proporcionaste.

Ese es un truco que me parece un poco frágil. Probablemente configuraría una aplicación adicional que solo se usa para pruebas con un modelo simple que luego puede usar para ejecutar esas funciones. Luego, podría usar fácilmente el ORM de Django para completar los datos en sus pruebas. Es un poco más de escritura y un par de archivos adicionales, pero entonces debería ser seguro para futuras roturas.

Si alguien más encuentra este problema: realizar la configuración de la base de datos en setup_function / setup_class / setup_module no es realmente compatible o posible de ninguna buena manera, ya que la configuración de la base de datos de pytest-django se basa en accesorios.

La solución es usar un dispositivo que solicite correctamente el dispositivo db:
http://pytest-django.readthedocs.org/en/latest/helpers.html#db

@pelme
Con el accesorio db es posible ejecutar dicha configuración solo en el alcance de la función, no en la clase, módulo o sesión. Por ejemplo, si necesitamos completar algunos registros en la base de datos antes de que se ejecuten las pruebas de clase.

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

¿Hay alguna otra forma de manejarlo?

Sí, esa es una limitación del dispositivo db tal como está implementado actualmente. En PR # 258 se ha trabajado para hacer posible la creación de un estado de base de datos que esté vinculado por el alcance de la clase / módulo / sesión.

Aunque este problema es bastante antiguo, me ha resultado útil encontrar la solución a un problema que estaba teniendo con pytest y pytest-django . Dado que pytest 3.5.0 hay un problema al usar los accesorios django_db mark y module level.

A continuación estaba funcionando antes de 3.5.0 (al menos no estaba causando ningún problema).

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

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

Después de 3.5.0 aumenta

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

La solución fue eliminar scope='module' .

+1 Para mí, simplemente cambiar de algunas pruebas unitarias iniciales de Djano, este es un gran inconveniente, al inicializar la base de datos para mis casos de prueba de API. En realidad, el soporte de accesorios de base de datos de sesiones / módulos debería ser una característica básica. ¿Alguna sugerencia de cómo resolver esto?

+1

¿Fue útil esta página
0 / 5 - 0 calificaciones