Ver también
El tutorial de pruebas <</intro/tutorial05>`, la referencia a las herramientas de pruebas </topics/testing/tools>` y los temas avanzados de pruebas </topics/testing/advanced>`.
Este documento se divide en dos secciones primarias. Primero, explicamos cómo escribir pruebas con Django. Luego, explicamos cómo ejecutarlas.
Las pruebas unitarias de Django utilizan un módulo de la biblioteca estándar de Python: unittest. Este módulo define las pruebas utilizando una aproximación basada en clases.
Aquí tienes un ejemplo que hereda de django.test.TestCase, que es una subclase de unittest.TestCase que ejecuta cada prueba dentro de una transacción para proporcionar aislamiento:
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
Cuando ejecutes tus pruebas <running-tests>, el comportamiento predeterminado de la utilidad de prueba es encontrar todas las clases de casos de prueba (es decir, subclases de unittest.TestCase) en cualquier archivo cuyo nombre comienza con test, construir automáticamente un conjunto de pruebas a partir de esas clases de casos de prueba y ejecutar ese conjunto.
Para obtener más detalles sobre unittest, consulta la documentación de Python.
¿Dónde deberían vivir las pruebas?
El template por defecto startapp crea un archivo tests.py en la nueva aplicación. Esto podría ser suficiente si solo tienes unos pocos tests, pero a medida que crece tu suite de pruebas, es probable que desees reestructurarla en un paquete de pruebas para poder dividir tus tests en submódulos diferentes como test_models.py, test_views.py, test_forms.py, etc. Puedes elegir cualquier esquema organizativo que te guste.
Ver también Probando aplicaciones reutilizables utilizando el ejecutor de pruebas de Django.
Advertencia
Si tus pruebas dependen del acceso a la base de datos, como crear o consultar modelos, asegúrate de crear tus clases de prueba como subclases de django.test.TestCase en lugar de unittest.TestCase.
Usando unittest.TestCase se evita el costo de ejecutar cada prueba en una transacción y vaciar la base de datos, pero si tus pruebas interactúan con la base de datos su comportamiento variará según el orden en que las ejecuta el ejecutor de pruebas. Esto puede dar lugar a pruebas unitarias que pasan cuando se ejecutan de forma aislada pero fallan cuando se ejecutan en un conjunto.
Una vez que hayas escrito las pruebas, ejecútalas utilizando el comando test de la utilidad manage.py de tu proyecto:
$ ./manage.py test
La traducción de los textos es la siguiente:
Puedes especificar pruebas particulares para ejecutar suministrando cualquier número de «etiquetas de prueba» a ./manage.py test. Cada etiqueta de prueba puede ser un camino completo de Python puntoado a un paquete, módulo, subclase de TestCase o método de prueba. Por ejemplo:
# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests
# Run all the tests found within the 'animals' package
$ ./manage.py test animals
# Run just one test case class
$ ./manage.py test animals.tests.AnimalTestCase
# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak
También puedes proporcionar un camino a un directorio para descubrir pruebas debajo de ese directorio:
$ ./manage.py test animals/
Puedes especificar un patrón de coincidencia de nombre de archivo personalizado utilizando la opción -p (o --pattern) si tus archivos de prueba tienen nombres diferentes del patrón test*.py:
$ ./manage.py test --pattern="tests_*.py"
Si presionas Ctrl-C mientras las pruebas están en ejecución, el ejecutor de pruebas esperará a que la prueba actualmente en ejecución termine y luego saldrá con normalidad. Durante una salida con normalidad, el ejecutor de pruebas mostrará detalles de cualquier falla de prueba, informará sobre cuántas pruebas se han ejecutado y cuántos errores y fallas se han encontrado, y destruirá las bases de datos de prueba como de costumbre. Por lo tanto, presionar Ctrl-C puede ser muy útil si olvidas pasar la opción --failfast , notas que algunas pruebas están fallando inesperadamente y quieres obtener detalles sobre las fallas sin esperar a que se complete la ejecución de pruebas completa.
Si no deseas esperar a que la prueba actualmente en ejecución termine, puedes presionar Ctrl-C una segunda vez y la ejecución de pruebas se detendrá inmediatamente, pero no con normalidad. No se mostrarán detalles sobre las pruebas ejecutadas antes de la interrupción y ninguna base de datos de prueba creada por la ejecución será destruida.
Ejecutar pruebas con advertencias habilitadas
Es una buena idea ejecutar tus pruebas con advertencias de Python habilitadas: python -Wa manage.py test. La bandera -Wa le dice a Python que muestre las advertencias de deprecación. Django, como muchos otros bibliotecas de Python, utiliza estas advertencias para señalar cuando se van a ir de moda características. También puede señalar áreas en tu código que no están estrictamente mal pero podrían beneficiarse de una implementación mejor.
Las pruebas que requieren una base de datos (a saber, las pruebas de modelos) no utilizarán tu «base de datos real» (de producción). Se crean bases de datos separadas y vacías para las pruebas.
Independientemente de si los tests pasan o fallan, las bases de datos de prueba se destruyen cuando todos los tests han sido ejecutados.
Puedes evitar que las bases de datos de prueba sean destruidas utilizando la opción test --keepdb. Esta opción preservará la base de datos de prueba entre ejecuciones. Si la base de datos no existe, se creará primero y se aplicarán cualquier migración para mantenerla actualizada.
Como se describe en la sección anterior, si un testeo es interrumpido forzosamente, la base de datos de prueba puede no ser destruida. En la siguiente ejecución, te preguntarás si quieres reutilizar o destruir la base de datos. Utiliza la opción test --noinput para suprimir esa pregunta y destruir automáticamente la base de datos. Esto puede ser útil cuando se ejecutan tests en un servidor de integración continua donde los tests pueden ser interrumpidos por un tiempo límite, por ejemplo.
Los nombres de las bases de datos de prueba predeterminadas se crean agregando test_ al valor de cada NAME en DATABASES. Cuando se utiliza SQLite, los tests utilizarán una base de datos en memoria por defecto (es decir, la base de datos se creará en memoria, evitando el sistema de archivos completamente!). El diccionario TEST en DATABASES ofrece una serie de configuraciones para personalizar tu base de datos de prueba. Por ejemplo, si deseas utilizar un nombre de base de datos diferente, especifica NAME en el diccionario TEST para cualquier base de datos en DATABASES.
En PostgreSQL, USER también necesitará acceso de lectura a la base de datos postgres incorporada.
Además de utilizar una base de datos separada, el ejecutor de tests utilizará todos los mismos ajustes de base de datos que tienes en tu archivo de configuración: ENGINE, USER, HOST, etc. La base de datos de prueba se crea por el usuario especificado por USER, así que asegúrate de que la cuenta del usuario tenga suficientes privilegios para crear una nueva base de datos en el sistema.
Para un control fino sobre el conjunto de caracteres de tu base de datos de prueba, utiliza la opción CHARSET TEST. Si estás utilizando MySQL, también puedes utilizar la opción COLLATION para controlar la collación particular utilizada por la base de datos de prueba. Consulta la documentación sobre configuraciones avanzadas <https://docs.djangoproject.com/en/4.1/ref/settings/>_ para obtener más detalles.
Si estás utilizando una base de datos en memoria con SQLite, se habilita el caché compartido <https://www.sqlite.org/sharedcache.html>, por lo que puedes escribir tests con la capacidad de compartir la base de datos entre hilos.
¿Buscas datos de tu base de datos de producción cuando estás ejecutando tests?
Si tu código intenta acceder a la base de datos cuando sus módulos se compilan, esto ocurrirá antes que la base de datos de prueba esté configurada, con resultados potencialmente inesperados. Por ejemplo, si tienes una consulta de base de datos en el código de nivel de módulo y existe una base de datos real, los datos de producción podrían contaminar tus tests. No es una buena idea tener consultas de base de datos a la importación en tu código de cualquier manera - reescribe tu código para que no lo haga.
Los métodos personalizados de la clase ready() también se aplican a ellos.
Ver también
El tema de pruebas con múltiples bases de datos avanzadas <topics-testing-advanced-multidb>.
Para garantizar que todo el código de la clase TestCase comience con una base de datos limpia, el ejecutor de pruebas de Django reordena las pruebas de la siguiente manera:
Primero se ejecutan todas las subclases de TestCase.
Luego, se ejecutan todas las demás pruebas basadas en Django (clases de casos de prueba basadas en SimpleTestCase, incluyendo TransactionTestCase) sin garantizar ni imponer ningún orden entre ellas.
Luego se ejecutan cualquier otra prueba de la clase unittest.TestCase (incluidos los doctests) que puedan alterar la base de datos sin restaurarla a su estado original.
Nota
El nuevo orden de las pruebas puede revelar dependencias inesperadas en el orden de los casos de prueba. Esto es el caso con los doctests que se basaban en el estado dejado en la base de datos por un test dado TransactionTestCase, deben ser actualizados para poder ejecutarse de manera independiente.
Nota
Los fallos detectados al cargar las pruebas se ordenan antes de todo lo anterior para obtener retroalimentación más rápida. Esto incluye cosas como módulos de prueba que no se encontraron o que no se pudieron cargar debido a errores de sintaxis.
Puedes randomizar y/o revertir el orden de ejecución dentro de grupos utilizando las opciones test --shuffle y --reverse. Esto puede ayudar a asegurarte de que tus pruebas sean independientes entre sí.
Cualquier datos iniciales cargados en las migraciones solo estarán disponibles en los tests TestCase y no en los tests TransactionTestCase, además de que solo lo harán en backends donde se admiten transacciones (la excepción más importante es MyISAM). Esto también es cierto para los tests que dependen de TransactionTestCase como LiveServerTestCase y StaticLiveServerTestCase.
Django puede recargar esos datos por ti en una base por caso de prueba estableciendo la opción serialized_rollback a True en el cuerpo del TestCase o TransactionTestCase, pero ten en cuenta que esto ralentizará ese conjunto de tests en aproximadamente 3x.
Las aplicaciones de terceros o aquellas que desarrollan contra MyISAM necesitarán establecer esta configuración; sin embargo, en general, deberías estar desarrollando tus propios proyectos contra una base de datos transaccional y utilizando TestCase para la mayoría de los tests, por lo que no necesitarás esta configuración.
La serialización inicial suele ser muy rápida, pero si deseas excluir algunas aplicaciones de este proceso (y acelerar ligeramente las ejecuciones de pruebas), puedes agregar esas aplicaciones a TEST_NON_SERIALIZED_APPS.
Para evitar que los datos serializados se carguen dos veces, estableciendo serialized_rollback=True deshabilita el señal post_migrate cuando se vacía la base de datos de pruebas.
Para TransactionTestCase, los datos de migración serializados se hacen disponibles durante setUpClass().
Independientemente del valor de la configuración DEBUG en tu archivo de configuración, todos los tests de Django se ejecutan con DEBUG=False. Esto asegura que el resultado observado de tu código coincida con lo que se verá en un entorno de producción.
Las cachés no se vacían después de cada test y ejecutar manage.py test fooapp puede insertar datos de los tests en la caché de un sistema en vivo si ejecutas tus tests en producción porque, a diferencia de las bases de datos, no se utiliza una «caché de pruebas» separada. Este comportamiento puede cambiar en el futuro.
Cuando ejecutes tus pruebas, verás un número de mensajes mientras el ejecutor de pruebas se prepara. Puedes controlar el nivel de detalle de estos mensajes con la opción verbosity en la línea de comandos:
Creating test database...
Creating table myapp_animal
Creating table myapp_mineral
Esto te dice que el ejecutor de pruebas está creando una base de datos de prueba, tal como se describe en la sección anterior.
Una vez creada la base de datos de prueba, Django ejecutará tus pruebas. Si todo va bien, verás algo así:
----------------------------------------------------------------------
Ran 22 tests in 0.221s
OK
Si hay fallos en las pruebas, sin embargo, verás detalles completos sobre cuáles pruebas fallaron:
======================================================================
FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
self.assertIs(future_poll.was_published_recently(), False)
AssertionError: True is not False
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
Una explicación completa de este error de salida está más allá del alcance de este documento, pero es bastante intuitivo. Puedes consultar la documentación de la biblioteca unittest de Python para obtener más detalles.
Ten en cuenta que el código de retorno para el script ejecutor de pruebas es 1 para cualquier número de pruebas fallidas (ya sea que el fallo se debiera a un error, una afirmación fallida o un éxito inesperado). Si todas las pruebas pasan, el código de retorno es 0. Esta característica es útil si estás utilizando el script ejecutor de pruebas en un script de shell y necesitas probar para el éxito o el fallo a ese nivel.
Mientras tus pruebas estén correctamente aisladas, puedes ejecutarlas en paralelo para ganar velocidad en hardware con múltiples núcleos. Consulta la opción test --parallel.
El algoritmo de hash por defecto es bastante lento por diseño. Si estás autenticando a muchos usuarios en tus pruebas, podrías querer usar un archivo de configuración personalizado y establecer la configuración PASSWORD_HASHERS en un algoritmo de hash más rápido:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.MD5PasswordHasher",
]
No olvides incluir también en PASSWORD_HASHERS cualquier algoritmo de hash utilizado en fijaciones, si las hay.
La opción test --keepdb preserva la base de datos de pruebas entre ejecuciones de pruebas. Omite las acciones de creación y destrucción que pueden disminuir significativamente el tiempo para ejecutar pruebas.
La clase InMemoryStorage es una forma conveniente de evitar el acceso al disco para archivos de medios. Todos los datos se mantienen en memoria, luego se descartan después de ejecutar las pruebas.
may 31, 2026