Pytest-django: pytest.mark.django_db não joga bem com setup_module ()

Criado em 14 set. 2013  ·  15Comentários  ·  Fonte: pytest-dev/pytest-django

Aqui está meu código de teste:

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

E eu recebo DatabaseError: relation "test" does not exist de test_fetch_val() . Eu também consigo

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

saída capturada. Parece que setup_module() é chamado antes que o banco de dados seja criado.

Comentários muito úteis

+1 Para mim, apenas mudando de alguns testes de unidade Djano iniciais, esta é uma grande desvantagem, ao inicializar o banco de dados para meus casos de teste de API. Na verdade, o suporte a dispositivos de banco de dados de sessão / módulo deve ser um recurso básico. Alguma sugestão de como resolver isso?

Todos 15 comentários

A marca django_db é baseada em fixtures, não tenho certeza de como comunicar-se entre fixtures e os métodos setup_ *.

Você poderia usar um fixture com escopo de módulo em vez disso para conseguir a mesma coisa? Ou seja, 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

Apenas tentei. Não funcionou. Eu ganho Database access not allowed, use the "django_db" mark to enable agora.
Além disso, test_table() não é executado (tentei levantar uma exceção lá)

Desculpe, deve ser use fixtures, não use fixture:

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

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

A remoção do parâmetro db do parâmetro resulta em falha do dispositivo, removendo o escopo = 'módulo' que faz o raciocínio funcionar, mas então test_table() é executado para cada teste, o que eu não quero.

Eu também tentei

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 quase funciona, mas o segundo teste falha de alguma forma com DatabaseError: relation "test" does not exist . Um mistério completo para mim.

Django e o marcador django_db funcionam da maneira que cada caso de teste roda em sua própria transação, portanto, usar django_db com uma fixação de nível de módulo que insere dados no banco de dados realmente não faz sentido.

Qual é o seu caso de uso aqui? Por que você está criando uma tabela de banco de dados "à mão" em seus testes, e não com o Django, mas ainda deseja usar o banco de dados de teste / cursor de banco de dados de teste do Django?

Você não conseguiria alcançar o que deseja apenas construindo um cursor de banco de dados simples?

(O último exemplo evita o ScopeMismatchError, mas falha no teste porque a transação é revertida após o primeiro teste, revertendo, portanto, a tabela de teste.)

Estou tentando testar alguns utilitários db de baixo nível, que usam o cursor django internamente - https://github.com/Suor/handy/blob/master/handy/db.py#L40

E eu acho que será muito mais complicado definir um modelo em models.py e então fixtures em algum formato django para testar isso. Isso seria 3 arquivos no total para testar a funcionalidade bastante básica.

Eu só quero executar algum código de inicialização antes de executar os testes para que eu tenha alguns dados para brincar.

Oh, eu fiz funcionar! Encapsular o SQL de inicialização em begin; ... commit; ajudou.

Muito obrigado por todas as dicas que você forneceu.

Esse é um hack que parece um pouco frágil para mim. Eu provavelmente configuraria um aplicativo extra que só é usado para testes com um modelo simples que você pode usar para executar essas funções. Você poderia simplesmente usar o ORM do Django para preencher os dados em seus testes. É um pouco mais de digitação e alguns arquivos extras, mas deve ser seguro para quebras futuras.

Se alguém encontrar este problema: fazer a configuração do banco de dados em setup_function / setup_class / setup_module não é realmente suportado ou possível de qualquer maneira, já que a configuração do banco de dados do pytest-django é baseada em fixtures.

A solução é usar um acessório que solicite adequadamente o db fixture:
http://pytest-django.readthedocs.org/en/latest/helpers.html#db

@pelme
Com o fixture db é possível executar tal configuração somente no escopo da função, não na classe, módulo ou sessão. Por exemplo, se precisarmos preencher alguns registros no banco de dados antes que os testes de classe sejam executados.

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

Existe alguma outra maneira de lidar com isso?

Sim, essa é uma limitação do dispositivo db conforme está implementado atualmente. No PR # 258, houve algum trabalho no sentido de possibilitar a criação de um estado de banco de dados vinculado ao escopo de classe / módulo / sessão.

Embora este problema seja bastante antigo, achei útil encontrar a solução para um problema que estava tendo com pytest e pytest-django . Como pytest 3.5.0 há um problema ao usar django_db mark e module luminárias de nível.

Abaixo estava funcionando antes de 3.5.0 (pelo menos não estava causando nenhum problema).

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

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

Depois de 3.5.0 ele aumenta

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

A solução foi remover scope='module' .

+1 Para mim, apenas mudando de alguns testes de unidade Djano iniciais, esta é uma grande desvantagem, ao inicializar o banco de dados para meus casos de teste de API. Na verdade, o suporte a dispositivos de banco de dados de sessão / módulo deve ser um recurso básico. Alguma sugestão de como resolver isso?

+1

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

mpasternak picture mpasternak  ·  5Comentários

rodrigorodriguescosta picture rodrigorodriguescosta  ·  4Comentários

blueyed picture blueyed  ·  7Comentários

mjk4 picture mjk4  ·  4Comentários

asfaltboy picture asfaltboy  ·  5Comentários