¿Cómo difundir las pruebas unitarias de django en varios archivos?


126
  • Tengo una aplicación python-django
  • Estoy usando el marco de pruebas unitarias
  • Las pruebas se organizan en el archivo "tests.py" en el directorio del módulo
  • Estoy ejecutando las pruebas a través de ./manage.py test app

Ahora..

  • El tests.pyarchivo se está volviendo bastante grande / complejo / desordenado
  • Me gustaría dividir tests.pyen colecciones más pequeñas de pruebas ...

¿Cómo?

Respuestas:


47

El comportamiento ha cambiado en Django 1.6, por lo que ya no es necesario crear un paquete. Solo nombra tus archivos test*.py.

De la documentación de Django 1.7

Cuando ejecuta sus pruebas, el comportamiento predeterminado de la utilidad de prueba es encontrar todos los casos de prueba (es decir, subclases de unittest.TestCase) en cualquier archivo cuyo nombre comience con prueba, construya automáticamente un conjunto de pruebas a partir de esos casos de prueba, y ejecuta esa suite.

De la documentación de Django 1.6 ,

El descubrimiento de prueba se basa en el descubrimiento de prueba incorporado del módulo unittest. De manera predeterminada, esto detectará pruebas en cualquier archivo llamado "prueba * .py" en el directorio de trabajo actual.

Comportamiento anterior, de la documentación de Django 1.5 :

Cuando ejecuta sus pruebas, el comportamiento predeterminado de la utilidad de prueba es encontrar todos los casos de prueba (es decir, subclases de unittest.TestCase) en models.py y tests.py, construye automáticamente un conjunto de pruebas a partir de esos casos de prueba, y ejecuta esa suite.

Hay una segunda forma de definir el conjunto de pruebas para un módulo: si define una función llamada suite () en models.py o tests.py, el corredor de pruebas de Django usará esa función para construir el conjunto de pruebas para ese módulo. Esto sigue la organización sugerida para las pruebas unitarias. Consulte la documentación de Python para obtener más detalles sobre cómo construir un conjunto de pruebas complejo.


44
En django 2.6 realmente no descubre nada ...
LtWorf

2
Actualmente usando Django 1.10, quería poner todos mis test*.pyarchivos en una carpeta llamada testspara mantener la carpeta limpia; esto es posible, pero debe ejecutar ./manage.py test app.testsy todas las importaciones relativas deben subir de nivel (se from .modelsconvierte from ..models).
Scott Stevens

123

Tenga en cuenta que este enfoque ya no es válido desde Django 1.6, consulte esta publicación .

Puede crear una testscarpeta con ___init___.pydentro (para que se convierta en un paquete). Luego agrega sus archivos .py de prueba dividida allí e importa todos ellos ___init___.py.

Es decir: sustituya el test.pyarchivo con un módulo que se vea y actúe como el archivo:

Crear un testsdirectorio debajo de la aplicación en cuestión

aplicación
app \ models.py
app \ views.py
aplicación \ pruebas
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Importe los submódulos a app\tests\__init__.py:

from bananas import *
from apples import *

Ahora puede usar ./manage.py como si todos estuvieran en un solo archivo:

./manage.py test app.some_test_in_bananas

1
Doh Querías decir crear un módulo de 'pruebas' bajo la aplicación que estoy probando; No es una nueva aplicación llamada pruebas. Ahora lo entiendo. Increíble. ¡Gracias!
John Mee

@ John: ¡Ya no puedo reconocer mi respuesta! :-) Pero tienes toda la razón de que era demasiado vago, incluso si es correcto: tus ejemplos lo dejan claro, contrario a mi redacción original.
Tomasz Zieliński

2
@Tomasz ... Tus palabras siguen ahí, totalmente intactas. Lo desarrollé un poco desde que me pusiste en el camino correcto.
John Mee

@John: No estaba enojado en absoluto si eso es lo que quieres decir :) Fue divertido ver mi propia respuesta en una forma un poco diferente
Tomasz Zieliński

44
@jMyles, si quiere decir "corredor de prueba regular de django" quiere decir que python manage.py test myapp, de hecho, esta respuesta funciona bien. (solo lo intenté)
Kirk Woll

27

La respuesta según lo declarado por Tomasz es correcta. Sin embargo, puede volverse tedioso asegurarse de que las importaciones __init__.pycoincidan con la estructura de su archivo.

Para detectar automáticamente todas las pruebas en la carpeta , puede agregar esto en __init__.py:

import unittest

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

Esto le permitirá ejecutar, ./manage.py test appnamepero no manejará la ejecución de pruebas específicas. Para hacer eso, puede usar este código (también en __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__)

Ahora puede ejecutar todas sus pruebas a través de manage.py test app o específicas a través demanage.py test app.TestApples


¿Dónde colocas la segunda pieza?
rh0dium

Ambas piezas entran__init__.py
Bryce Drennan

Tenga en cuenta que si alguno de los nombres de sus paquetes de prueba coincide con los nombres de módulos de nivel superior que se importan durante la ejecución de la prueba, el fragmento pkgutil hará que la importación falle porque las pruebas se agregan como sys.modules[packagename]. Una solución rápida es para delcualquiera que cause problemas después de lo anterior. (O podría cambiar el nombre de sus carpetas;))
Paul Fenney

Esto es genial, pero me encontré con un error en el que, al ejecutar una prueba de nivel de aplicación ( python manage.py test appName), el segundo bit de código arrojaría un error que indicaba que __path__no estaba disponible. Lo evité envolviendo el segundo fragmento en un if '__path__' in locals():cheque, lo que funcionó. ¡Gracias por la respuesta!
alukach

1
+1 esto también asegura que el archivo init se adhiere a los estándares de codificación comunes, es decir, no tiene * o importaciones no utilizadas
Martin B.

13

Simplemente haga su estructura de directorio de esta manera:

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

Y python manage.py test myappfuncionará como se espera.



2

No es necesario codificar nada en init. Simplemente cree un subdirectorio en su aplicación. El único requisito es no llamarlo pruebas * Por ejemplo

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py

1
¿Por qué no puedes llamarlo algo que comienza con "pruebas"?
Serp C

Estoy usando esta respuesta con Django 1.11.4. Razones para usarlo: (1) El archivo "app / testing / __ init__.py" permanece vacío y (2) El comando sigue siendo la "aplicación de prueba python manage.py"
básica

2

Con Django 2.2, una solución simple y bastante buena podría ser crear una testcarpeta dentro de una aplicación, y puede poner sus test_...pyarchivos relacionados , simplemente agregarlos __init__.pya la testcarpeta.


1

Si tiene una configuración más complicada, o no desea usar from ... import *sentencias de tipo, puede definir una función llamada suiteen su tests.py (o tests / __ init__.py), que devuelve una instancia deunittest.TestSuite .


0

Yo creo que ./manage.py test simplemente ejecuta el truco de todas las pruebas (en django> = 1.7).

Si sus pruebas de organización son sobre agrupación y selección de cerezas y es fanático de noseusar django nose :

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

Si conoce nose, entonces sabe cómo "comodín" mucho mejor en todos sus archivos.

PD

Es solo una mejor práctica. Espero que ayude. La respuesta se tomó prestada aquí: ejecutar un caso de prueba específico en Django cuando su aplicación tiene un directorio de pruebas


0

Tengo dos archivos Uno es tests.pyy otro es test_api.py. Puedo ejecutar estos individualmente como a continuación.

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

Consulte la respuesta de @ osa sobre la convención de nomenclatura de archivos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.