Desative as migrações ao executar testes de unidade no Django 1.7


110

Django 1.7 introduziu migrações de banco de dados .

Ao executar os testes de unidade no Django 1.7, ele força uma migração , que leva muito tempo. Então, eu gostaria de pular as migrações do django e criar o banco de dados no estado final.

Sei que ignorar as migrações pode ser uma prática ruim, pois essa parte do código não seria testada. Mas não é o caso: estou executando as migrações completas no servidor de teste CI (jenkins). Eu só quero pular as migrações em meus testes locais, onde a velocidade é importante.


Algum contexto:

Até o Django 1.6 , ao usar South, eu usava a configuração SOUTH_TESTS_MIGRATE :

Por padrão, o comando syncdb do South também aplicará migrações se for executado no modo não interativo, o que inclui quando você estiver executando testes - ele executará todas as migrações sempre que você executar seus testes.

Se você deseja que o executor de teste use syncdb em vez de migrar - por exemplo, se suas migrações estão demorando muito para serem aplicadas - simplesmente defina SOUTH_TESTS_MIGRATE = False em settings.py.

No entanto, o syncdb não existe mais, agora é migrar .

E a partir do Django 1.8 , usarei o parâmetro --keepdb :

A opção --keepdb pode ser usada para preservar o banco de dados de teste entre execuções de teste. Isso tem a vantagem de ignorar as ações de criação e destruição, o que diminui muito o tempo de execução dos testes, especialmente aqueles em um grande conjunto de testes. Se o banco de dados de teste não existir, ele será criado na primeira execução e, em seguida, preservado para cada execução subsequente. Todas as migrações não aplicadas também serão aplicadas ao banco de dados de teste antes de executar o conjunto de testes.

Portanto, esta questão está limitada ao Django 1.7.


Eu diria que durante o UT, você realmente não está executando as migrações de uma forma que as teste, uma vez que o banco de dados com o qual você começou é inexistente. O teste de migrações realmente só acontece quando você migra um banco de dados existente. Este negócio de migração 1.7 é a primeira dificuldade real que tive com Django, mas é realmente uma grande irritação. O Sul pelo menos acertou o cenário de teste para migrações.
boatcoder

O django-test-without-migrationspacote tem sido muito útil para mim, você pode alterar a resposta aceita para stackoverflow.com/a/28993456/200224
Andy

Eu prefiro evitar adicionar novas dependências, se possível.
David Arcos

Respostas:


79

Veja esta solução alternativa , postada por Bernie Sumption na lista de discussão de desenvolvedores Django:

Se makemigrations ainda não foi executado, o comando "migrate" trata um aplicativo como não migrado e cria tabelas diretamente dos modelos, assim como o syncdb fazia no 1.6. Eu defini um novo módulo de configurações apenas para testes de unidade chamado "settings_test.py", que importa * do módulo de configurações principal e adiciona esta linha:

MIGRATION_MODULES = {"myapp": "myapp.migrations_not_used_in_tests"}

Então eu executo testes como este:

DJANGO_SETTINGS_MODULE = "myapp.settings_test" teste python manage.py

Esses tolos migram pensando que o aplicativo não foi migrado e, portanto, sempre que um banco de dados de teste é criado, ele reflete a estrutura atual de models.py.

No Django 1.9, essa situação melhorou um pouco e você pode definir o valor para None:

MIGRATION_MODULES = {"myapp": Nenhum}


9
Observe que o myapp.migrations_not_used_in_testsmódulo não deve existir.
bmihelac

4
Além do comentário que @bmihelac fez sobre o módulo não existir, a string do módulo deve conter a substring 'migrações', Para saber por que, consulte: github.com/django/django/blob/stable/1.7.x/django/db/migrations /…
nealtodd

7
A essência de uma função para construir MIGRATION_MODULES dinamicamente em settings_test.py: gist.github.com/nealtodd/2869341f38f5b1eeb86d
nealtodd

1
TY. Consegui reduzir meus testes de unidade de 13 segundos para 4 segundos por causa disso. Além disso, mais ganhos de velocidade podem ser encontrados usando sqlite para teste. Para mim, usar o postgres para testes está levando 5,5 segundos, mas o sqlite está levando 4 segundos.
Gattster de

21
Dos comentários da essência de @ nealtodd, aqui está um link para uma solução que evita algumas das armadilhas e é super simples: gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
djsutho

72

Aqui está o final do meu arquivo de configurações:

class DisableMigrations(object):

    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None


TESTS_IN_PROGRESS = False
if 'test' in sys.argv[1:] or 'jenkins' in sys.argv[1:]:
    logging.disable(logging.CRITICAL)
    PASSWORD_HASHERS = (
        'django.contrib.auth.hashers.MD5PasswordHasher',
    )
    DEBUG = False
    TEMPLATE_DEBUG = False
    TESTS_IN_PROGRESS = True
    MIGRATION_MODULES = DisableMigrations()

com base neste trecho

Desativei as migrações apenas quando os testes estão em execução


1
Agradável! Eu adicionaria o __setitem__(self, *_)método também porque tivemos problemas com aplicativos que definem sua própria migração, como settings.MIGRATION_MODULES['chroniker'] = 'db_migrations'
Zhe Li

1
Muito obrigado por isso, é a única coisa que achei que realmente funciona.
fluffels de

Isso não funciona mais no Django 1.9 ao executar testes em modo paralelo. Usando o teste normal não paralelo, ele continua a funcionar bem, mas alternar para o modo paralelo resulta em erros de que as tabelas não estão sendo encontradas.
LS55321

@LeeSemel em modo paralelo você provavelmente deseja usar a solução de rlmv
Guillaume Vincent

@guillaumevincent eu tenho o mesmo problema ao usar django-test-without-migrations em modo paralelo
LS55321


3

Atualização : Não importa, essa mudança foi revertida antes do lançamento do 1.10 final. Esperançosamente ele retornará em uma versão futura.


Note que a partir do Django 1.10 isso pode ser controlado por uma configuração de banco de dados de teste.

MIGRAR

Padrão: True

Se definido como False, Django não usará migrações para criar o banco de dados de teste.



1

Para django 1.9 e superior, a resposta de Guillaume Vincent não funciona mais, então aqui está uma nova solução:

Estou usando este snippet no meu arquivo de configurações, após a definição do INSTALLED_APPS

if os.environ.get('TESTS_WITHOUT_MIGRATIONS', False):
    MIGRATION_MODULES = {
        app.split('.')[-1]: None for app in INSTALLED_APPS
    }

Ele itera sobre todos os aplicativos instalados e marca cada um como não tendo módulo de migração. Veja a documentação do django para mais informações .

Usando este snippet você pode executar seus testes, definindo a variável de ambiente TESTS_WITHOUT_MIGRATIONS, por exemplo:

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

1

Acabei de descobrir como desabilitar migrações depois do django 1.10, pode ser que possa ajudar alguém. Aqui está o link do git

class DisableMigrations(dict):
    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

Migrations for django 1.10 tem duas partes, por favor, olhe para load_disk e gravador

A parte de load_diskpara o modelo de migração do aplicativo que deve ser adicionado em INSTALL_APP E a parte de recorderpara a conexão do banco de dados Para a versão anterior à 1.9, precisamos definir MIGRATION_MODULES={'do.not.migrate':'notmigrations'}quando você estiver executando o teste Agora precisamos defini-lo Nenhum como MIGRATION_MODULES={'do.not.migrate':None} Então, se não quisermos fazer migrações para nenhum aplicativo , basta estender um dict e retornar Nonepara a getitemfunção e fazer o mesmo em DATABASES, essa é a coisa certa que você precisa fazer

PS: Para o comando, você precisa especificar --setting=module.path.settings_test_snippetapós test PPS. Se você estiver trabalhando com pycharm, não defina --settings opções em Run/Debug configurations, apenas adicione o caminho desettings_test_snippet.py em Configuração personalizada. Isso fica bem !!

desfrutar

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.