Como espalhar testes de unidade do django em vários arquivos?

126
  • Eu tenho um aplicativo python-django
  • Estou usando a estrutura de teste de unidade
  • Os testes estão organizados no arquivo "tests.py" no diretório do módulo
  • Estou executando os testes via ./manage.py test app

Agora..

  • O tests.pyarquivo está ficando grande / complexo / bagunçado
  • Eu gostaria de dividir tests.pyem coleções menores de testes ...

Quão?

John Mee
fonte

Respostas:

47

O comportamento mudou no Django 1.6, então não há mais a necessidade de criar um pacote. Apenas nomeie seus arquivos test*.py.

Da documentação do Django 1.7

Quando você executa seus testes, o comportamento padrão do utilitário de teste é encontrar todos os casos de teste (ou seja, subclasses de unittest.TestCase) em qualquer arquivo cujo nome comece com test, crie automaticamente um conjunto de testes a partir desses casos, e execute esse conjunto.

Da documentação do Django 1.6 ,

A descoberta de teste é baseada na descoberta de teste integrada do módulo mais unido. Por padrão, isso descobrirá testes em qualquer arquivo chamado "test * .py" no diretório de trabalho atual.

Comportamento anterior, da documentação do Django 1.5 :

Quando você executa seus testes, o comportamento padrão do utilitário de teste é encontrar todos os casos de teste (ou seja, subclasses de unittest.TestCase) em models.py e tests.py, criar automaticamente um conjunto de testes a partir desses casos de teste, e execute esse conjunto.

Existe uma segunda maneira de definir o conjunto de testes para um módulo: se você definir uma função chamada suite () em models.py ou tests.py, o executor de testes do Django usará essa função para construir o conjunto de testes para esse módulo. Isso segue a organização sugerida para testes de unidade. Consulte a documentação do Python para obter mais detalhes sobre como construir um conjunto de testes complexo.

osa
fonte
4
No Django 2.6 ele realmente não descobrir nada ...
LtWorf
2
Atualmente usando o Django 1.10, eu queria colocar todos os meus test*.pyarquivos em uma pasta chamada testspara manter a pasta limpa - isso é possível, mas você deve executar ./manage.py test app.testse todas as importações relativas precisam subir de nível ( from .modelsse torna from ..models).
Scott Stevens
123

Note que esta abordagem não é mais válida no Django 1.6, veja este post .

Você pode criar uma testspasta com ___init___.pyinside (para que se torne um pacote). Depois, adicione seus arquivos .py de teste de divisão e importe todos eles ___init___.py.

Ou seja: Substitua o test.pyarquivo por um módulo que se parece com o arquivo:

Crie um testsdiretório no aplicativo em questão

aplicativo
app \ models.py
app \ views.py
app \ tests
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Importe os submódulos para app\tests\__init__.py:

from bananas import *
from apples import *

Agora você pode usar ./manage.py como se todos estivessem em um único arquivo:

./manage.py test app.some_test_in_bananas
Tomasz Zieliński
fonte
1
Doh. Você queria criar um módulo de 'testes' no aplicativo que estou testando; não é uma nova aplicação chamada testes. Agora eu entendi. Impressionante. Obrigado!
John Mee
@ John: Não consigo mais reconhecer minha resposta! :-) Mas você está completamente certo de que era muito vago, mesmo que correto - seus exemplos deixam claro, ao contrário da minha redação original.
Tomasz Zieliński
2
@ Tomasz .. Suas palavras ainda estão lá - totalmente intactas. Eu apenas desenvolvi um pouco desde que você me colocou no caminho certo.
John Mee
@ John: Eu não estava com raiva de todos, se é isso que você quer dizer :) Era apenas engraçado ver minha própria resposta em uma forma pouco diferente
Tomasz Zieliński
4
@jMyles, se você quer dizer com "corredor de teste regular do django" python manage.py test myapp, na verdade essa resposta funciona muito bem. (só tentei)
Kirk Woll
27

A resposta conforme declarada por Tomasz está correta. No entanto, pode ser entediante garantir que as importações __init__.pycorrespondam à sua estrutura de arquivos.

Para detectar automaticamente todos os testes na pasta, você pode adicioná-lo em __init__.py:

import unittest

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

Isso permitirá que você execute, ./manage.py test appnamemas não lida com a execução de testes específicos. Para fazer isso, você pode usar este código (também em __init__.py):

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

Agora você pode executar todos os seus testes via manage.py test appou testes específicos viamanage.py test app.TestApples

Bryce Drennan
fonte
Onde você coloca a segunda peça?
amigos estão dizendo sobre rh0dium
Ambas as peças entrar__init__.py
Bryce Drennan
Observe que, se algum nome de seu pacote de teste coincidir com nomes de módulo de nível superior importados durante a execução do teste, o snippet pkgutil fará com que a importação falhe porque os testes foram adicionados como sys.modules[packagename]. Uma solução rápida é para delqualquer um que cause problemas após o exposto acima. (Ou você pode renomear as pastas;))
Paul Fenney
Isso é ótimo, mas ocorreu um erro em que, ao executar um teste no nível do aplicativo ( python manage.py test appName), o segundo bit de código gerava um erro informando que __path__não estava disponível. Eu o evitei envolvendo o segundo trecho em uma if '__path__' in locals():verificação, o que fez o truque. Obrigado pela resposta!
alukach
1
+1 isso também garante que os Init adere arquivo para padrões de codificação comuns, ou seja, não tem * ou não utilizados importações
Martin B.
13

Apenas faça sua estrutura de diretórios assim:

myapp/
    __init__.py
    tests/
        __init__.py
        test_one.py
        test_two.py
        ...
    ...

E python manage.py test myappfuncionará como esperado.

spiderlama
fonte
5

http://docs.python.org/library/unittest.html#organizing-tests fala sobre como dividir os arquivos em módulos, e a seção logo acima tem um exemplo.

Jim Deville
fonte
2
O 'bit extra' que estou procurando, através do rtfm, é o ambiente de configurações do django, o banco de dados e os acessórios para os testes.
John Mee
2

Não é necessário codificar nada no init. Basta criar um subdiretório no seu aplicativo. O único requisito é não chamá-lo de testes * Por exemplo

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py
MaxBlax360
fonte
1
Por que você não pode chamá-lo de algo que começa com "testes"?
Serp C
Estou usando esta resposta com o Django 1.11.4. Razões para usá-lo: (1) O arquivo "app / testing / __ init__.py" permanece vazio e (2) O comando continua sendo o "aplicativo de teste python manage.py"
básico
2

Com o Django 2.2, uma solução simples e bastante boa pode ser criar uma testpasta dentro de um aplicativo, e você pode colocar seus test_...pyarquivos relacionados , basta adicioná __init__.py- los à testpasta.

Gabor
fonte
1

Se você tiver uma configuração mais complicada ou não quiser usar as from ... import *instruções -type, poderá definir uma função chamadasuite em tests.py (ou tests / __ init__.py), que retornará uma instância de unittest.TestSuite.

Joel Cross
fonte
0

eu acho que ./manage.py test simplesmente executa todos os truques de teste (no django> = 1.7).

Se seus testes de organização são sobre agrupamento e seleção de cerejeira e você é fã de noseusar nariz de django :

python manage.py test another.test:TestCase.test_method

Se você conhece o nariz, sabe como "curinga" muito melhor em todos os seus arquivos.

PS

É apenas uma prática melhor. Espero que ajude. A resposta foi emprestada daqui: Executando um caso de teste específico no Django quando seu aplicativo tem um diretório de testes

Yauhen Yakimovich
fonte
0

Eu tenho dois arquivos Um é tests.pye outro é test_api.py. Eu posso executá-los individualmente como abaixo.

   manage.py test companies.tests
   manage.py test companies.test_api

Consulte a resposta do @ osa sobre a convenção de nomenclatura de arquivos.

kta
fonte