Temas avanzados de pruebas

La fábrica de solicitudes

class RequestFactory[fuente]

La RequestFactory comparte la misma API que el cliente de pruebas. Sin embargo, en lugar de comportarse como un navegador, la RequestFactory proporciona una forma de generar una instancia de solicitud que se puede utilizar como primer argumento para cualquier vista. Esto significa que puedes probar una función de vista de la misma manera que probarías cualquier otra función – como una caja negra, con exactamente conocidos inputs, probando específicos outputs.

La API para la RequestFactory es un ligeramente restringido conjunto de subconjunto de la API del cliente de pruebas:

  • Solo tiene acceso a los métodos HTTP: get(), post(), put(), delete(), head(), options() y trace().

  • Estos métodos aceptan todos los mismos argumentos excepto para follow. Dado que esto es solo una fábrica para producir solicitudes, le corresponde a usted manejar la respuesta.

  • No admite middleware. Los atributos de sesión y autenticación deben ser suministrados por la prueba misma si se requieren para que la vista funcione correctamente.

Se agregó el parámetro query_params.

Ejemplo

A continuación, se muestra un ejemplo de prueba unitaria utilizando la fábrica de solicitudes:

from django.contrib.auth.models import AnonymousUser, User
from django.test import RequestFactory, TestCase

from .views import MyView, my_view


class SimpleTest(TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()
        self.user = User.objects.create_user(
            username="jacob", email="jacob@…", password="top_secret"
        )

    def test_details(self):
        # Create an instance of a GET request.
        request = self.factory.get("/customer/details")

        # Recall that middleware are not supported. You can simulate a
        # logged-in user by setting request.user manually.
        request.user = self.user

        # Or you can simulate an anonymous user by setting request.user to
        # an AnonymousUser instance.
        request.user = AnonymousUser()

        # Test my_view() as if it were deployed at /customer/details
        response = my_view(request)
        # Use this syntax for class-based views.
        response = MyView.as_view()(request)
        self.assertEqual(response.status_code, 200)

AsyncRequestFactory

class AsyncRequestFactory[fuente]

La RequestFactory crea solicitudes WSGI-like. Si desea crear solicitudes ASGI-like, incluyendo tener un correcto scope ASGI, en su lugar puede utilizar django.test.AsyncRequestFactory.

Esta clase es directamente API-compatible con RequestFactory, con la única diferencia de que devuelve instancias de ASGIRequest en lugar de instancias de WSGIRequest. Todas sus métodos aún son llamables sincrónicas.

Los argumentos de palabra clave arbitrarios en defaults se agregan directamente al ámbito ASGI.

Se agregó el parámetro query_params.

Pruebas de vistas basadas en clase

Para probar vistas basadas en clase fuera del ciclo solicitud/respuesta, debes asegurarte de que estén configuradas correctamente, llamando a setup() después de la instanciación.

Por ejemplo, suponiendo la siguiente vista basada en clase:

views.py
from django.views.generic import TemplateView


class HomeView(TemplateView):
    template_name = "myapp/home.html"

    def get_context_data(self, **kwargs):
        kwargs["environment"] = "Production"
        return super().get_context_data(**kwargs)

Puedes probar directamente el método get_context_data() creando una instancia de la vista, pasándole un request a setup(), antes de proceder con el código de tu prueba:

tests.py
from django.test import RequestFactory, TestCase
from .views import HomeView


class HomePageTest(TestCase):
    def test_environment_set_in_context(self):
        request = RequestFactory().get("/")
        view = HomeView()
        view.setup(request)

        context = view.get_context_data()
        self.assertIn("environment", context)

Pruebas y nombres de host múltiples

La configuración ALLOWED_HOSTS se valida al ejecutar pruebas. Esto permite que el cliente de pruebas diferencie entre URLs internas y externas.

Los proyectos que admiten multitenencia o alteran la lógica empresarial según el host de la solicitud y utilizan nombres de host personalizados en las pruebas deben incluir esos hosts en ALLOWED_HOSTS.

La primera opción para hacerlo es agregar los hosts a tu archivo de configuración. Por ejemplo, el conjunto de pruebas para docs.djangoproject.com incluye lo siguiente:

from django.test import TestCase


class SearchFormTestCase(TestCase):
    def test_empty_get(self):
        response = self.client.get(
            "/en/dev/search/",
            headers={"host": "docs.djangoproject.dev:8000"},
        )
        self.assertEqual(response.status_code, 200)

Los textos traducidos manteniendo todas sus etiquetas intactas son:

ALLOWED_HOSTS = ["www.djangoproject.dev", "docs.djangoproject.dev", ...]

Otra opción es agregar los hosts requeridos a la lista de ALLOWED_HOSTS utilizando override_settings() o modify_settings(). Esta opción puede ser preferible en aplicaciones independientes que no pueden empaquetar su propio archivo de configuración o para proyectos donde la lista de dominios no es estática (por ejemplo, subdominios para multitenencia). Por ejemplo, podrías escribir una prueba para el dominio http://otherserver/ de la siguiente manera:

from django.test import TestCase, override_settings


class MultiDomainTestCase(TestCase):
    @override_settings(ALLOWED_HOSTS=["otherserver"])
    def test_other_domain(self):
        response = self.client.get("http://otherserver/foo/bar/")

Desactivar la comprobación de ALLOWED_HOSTS (ALLOWED_HOSTS = ['*']) al ejecutar pruebas impide que el cliente de pruebas levante un mensaje de error útil si sigue una redirección a una URL externa.

Pruebas y bases de datos múltiples

Probando configuraciones primaria/replica

Si estás probando una configuración de base de datos múltiple con replicación primaria/replica (referred a como maestro/esclavo por algunas bases de datos), esta estrategia de crear bases de datos de prueba plantea un problema. Cuando las bases de datos de prueba se crean, no habrá ninguna replicación y como resultado, los datos creados en la base primaria no serán visibles en la replica.

Para compensar esto, Django permite definir que una base de datos es un espejo de pruebas. Considera el siguiente (simplificado) ejemplo de configuración de bases de datos:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myproject",
        "HOST": "dbprimary",
        # ... plus some other settings
    },
    "replica": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myproject",
        "HOST": "dbreplica",
        "TEST": {
            "MIRROR": "default",
        },
        # ... plus some other settings
    },
}

En este setup, tenemos dos servidores de bases de datos: dbprimary, descrito por la alias de base de datos default, y dbreplica descrita por la alias replica. Como podrías esperar, dbreplica ha sido configurado por el administrador de bases de datos como una replica de lectura de dbprimary, por lo que en actividad normal, cualquier escritura a default aparecerá en replica.

Si Django creara dos bases de datos de prueba independientes, esto rompería cualquier prueba que esperara la replicación. Sin embargo, la base de datos replica ha sido configurada como un espejo de pruebas (utilizando el MIRROR parámetro de configuración de pruebas), indicando que bajo testing, replica debe ser tratado como un espejo de default.

Cuando se configura el entorno de prueba, una versión de prueba de replica no será creada. En su lugar, la conexión a replica será redirigida para apuntar a default. Como resultado, las escrituras en default aparecerán en replica – pero porque son realmente la misma base de datos, no porque haya replicación de datos entre las dos bases de datos. Como esto depende de transacciones, las pruebas deben utilizar TransactionTestCase en lugar de TestCase.

Control del orden de creación para bases de datos de prueba

Por defecto, Django supondrá que todas las bases de datos dependen de la base de datos default y, por lo tanto, siempre creará la base de datos default primero. Sin embargo, no se hacen garantías sobre el orden de creación de ninguna otra base de datos en su configuración de prueba.

Si la configuración de su base de datos requiere un orden específico de creación, puede especificar las dependencias que existen utilizando la configuración de prueba DEPENDENCIES. Considere el siguiente ejemplo de configuración de bases de datos simplificada:

DATABASES = {
    "default": {
        # ... db settings
        "TEST": {
            "DEPENDENCIES": ["diamonds"],
        },
    },
    "diamonds": {
        # ... db settings
        "TEST": {
            "DEPENDENCIES": [],
        },
    },
    "clubs": {
        # ... db settings
        "TEST": {
            "DEPENDENCIES": ["diamonds"],
        },
    },
    "spades": {
        # ... db settings
        "TEST": {
            "DEPENDENCIES": ["diamonds", "hearts"],
        },
    },
    "hearts": {
        # ... db settings
        "TEST": {
            "DEPENDENCIES": ["diamonds", "clubs"],
        },
    },
}

Bajo esta configuración, la base de datos diamonds se creará primero, ya que es el único alias de base de datos sin dependencias. Los alias default y clubs se crearán a continuación (aunque no se garantiza el orden de creación de este par), luego hearts, y finalmente spades.

Si existen cualquier tipo de dependencias circulares en la definición DEPENDENCIES, se levantará una excepción ImproperlyConfigured.

Características avanzadas de TransactionTestCase

TransactionTestCase.available_apps

Advertencia

Esta atributo es una API privada. Puede cambiar o eliminarse sin un período de desprecación en el futuro, por ejemplo para adaptarse a cambios en la carga de aplicaciones.

Se utiliza para optimizar el conjunto de pruebas de Django, que contiene cientos de modelos pero no relaciones entre modelos de diferentes aplicaciones.

Por defecto, available_apps está configurado como None. Después de cada prueba, Django llama a flush para resetear el estado de la base de datos. Esto vacía todas las tablas y emite el señal post_migrate, que recrea un tipo de contenido y cuatro permisos para cada modelo. Esta operación se vuelve costosa en proporción al número de modelos.

Configurando available_apps como una lista de aplicaciones instruye a Django para comportarse como si solo los modelos de estas aplicaciones estuvieran disponibles. El comportamiento de TransactionTestCase cambia de la siguiente manera:

  • post_migrate se dispara antes de cada prueba para crear los tipos de contenido y permisos para cada modelo en las aplicaciones disponibles, en caso de que falten.

  • Después de cada prueba, Django vacía solo las tablas correspondientes a modelos en aplicaciones disponibles. Sin embargo, a nivel de base de datos, la truncación puede propagarse a modelos relacionados en aplicaciones no disponibles. Además post_migrate no se dispara; se disparará por el siguiente TransactionTestCase, después del conjunto correcto de aplicaciones seleccionadas.

Dado que la base de datos no está completamente vaciada, si una prueba crea instancias de modelos no incluidos en available_apps, estos permanecerán y pueden causar que pruebas no relacionadas fallen. Ten cuidado con las pruebas que utilizan sesiones; el motor de sesión por defecto almacena las sesiones en la base de datos.

Dado que post_migrate no se emite después de vaciar la base de datos, su estado después de un TransactionTestCase no es el mismo que después de un TestCase: le faltan las filas creadas por los oyentes a post_migrate. Considerando el orden en que se ejecutan las pruebas, esto no es un problema, siempre y cuando todos los TransactionTestCase de una suite de pruebas determinada declaren available_apps, o ninguno de ellos.

available_apps es obligatorio en la suite de pruebas propia de Django.

TransactionTestCase.reset_sequences

Establecer reset_sequences = True en un TransactionTestCase asegurará que las secuencias se reseteen siempre antes del inicio de la prueba:

class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
    reset_sequences = True

    def test_animal_pk(self):
        lion = Animal.objects.create(name="lion", sound="roar")
        # lion.pk is guaranteed to always be 1
        self.assertEqual(lion.pk, 1)

A menos que estés explícitamente probando números de secuencia de clave primaria, se recomienda no codificar valores de clave primaria en pruebas.

Usar reset_sequences = True ralentizará la prueba, ya que el reseteo de la clave primaria es una operación de base de datos relativamente costosa.

Hacer cumplir que las clases de prueba se ejecuten secuencialmente

Si tienes clases de prueba que no pueden ejecutarse en paralelo (por ejemplo, porque comparten un recurso común), puedes utilizar django.test.testcases.SerializeMixin para ejecutarlas secuencialmente. Esta mezcla utiliza un archivo de bloqueo del sistema de archivos.

Ejemplo: puedes utilizar __file__ para determinar que todas las clases de prueba en el mismo archivo que hereden de SerializeMixin se ejecutarán secuencialmente:

import os

from django.test import TestCase
from django.test.testcases import SerializeMixin


class ImageTestCaseMixin(SerializeMixin):
    lockfile = __file__

    def setUp(self):
        self.filename = os.path.join(temp_storage_dir, "my_file.png")
        self.file = create_file(self.filename)


class RemoveImageTests(ImageTestCaseMixin, TestCase):
    def test_remove_image(self):
        os.remove(self.filename)
        self.assertFalse(os.path.exists(self.filename))


class ResizeImageTests(ImageTestCaseMixin, TestCase):
    def test_resize_image(self):
        resize_image(self.file, (48, 48))
        self.assertEqual(get_image_size(self.file), (48, 48))

Probando aplicaciones reutilizables utilizando el ejecutor de pruebas de Django

Si estás escribiendo una aplicación reutilizable , es posible que desees utilizar el ejecutor de pruebas de Django para ejecutar tu propio conjunto de pruebas y así aprovechar la infraestructura de pruebas de Django.

Una práctica común es un directorio de pruebas junto al código de la aplicación, con la siguiente estructura:

runtests.py
polls/
    __init__.py
    models.py
    ...
tests/
    __init__.py
    models.py
    test_settings.py
    tests.py

Vamos a echar un vistazo dentro de uno o dos de esos archivos:

runtests.py
#!/usr/bin/env python
import os
import sys

import django
from django.conf import settings
from django.test.utils import get_runner

if __name__ == "__main__":
    os.environ["DJANGO_SETTINGS_MODULE"] = "tests.test_settings"
    django.setup()
    TestRunner = get_runner(settings)
    test_runner = TestRunner()
    failures = test_runner.run_tests(["tests"])
    sys.exit(bool(failures))

Este es el script que invocarás para ejecutar la suite de pruebas. Configura el entorno de Django, crea la base de datos de prueba y ejecuta las pruebas.

Para la claridad de este ejemplo, se incluye solo lo mínimo necesario para utilizar el ejecutor de pruebas de Django. Es posible que desees agregar opciones de línea de comandos para controlar la verbosidad, pasar etiquetas de prueba específicas para su ejecución, etc.

tests/test_settings.py
SECRET_KEY = "fake-key"
INSTALLED_APPS = [
    "tests",
]

Este archivo contiene las configuraciones de Django necesarias para ejecutar los pruebas de tu aplicación.

De nuevo, este es un ejemplo mínimo; tus pruebas pueden requerir ajustes adicionales para ejecutarse.

Dado que el paquete tests está incluido en INSTALLED_APPS cuando se ejecutan tus pruebas, puedes definir modelos solo de prueba en su archivo models.py.

Uso de diferentes frameworks de testing

Claramente, unittest no es el único framework de testing de Python. Si bien Django no proporciona un soporte explícito para marcos alternativos, sí proporciona una forma de invocar pruebas construidas para un marco alternativo como si fueran pruebas normales de Django.

Cuando ejecutas ./manage.py test, Django mira en la configuración TEST_RUNNER para determinar qué hacer. Por defecto, TEST_RUNNER apunta a 'django.test.runner.DiscoverRunner'. Esta clase define el comportamiento de testing por defecto de Django. Este comportamiento implica:

  1. Ejecutando la configuración pre-test global.

  2. Buscando pruebas en cualquier archivo debajo del directorio actual cuyo nombre coincida con el patrón test*.py.

  3. Creando las bases de datos de prueba.

  4. Ejecutando migrate para instalar modelos e información inicial en las bases de datos de prueba.

  5. Ejecutando los comprobaciones del sistema.

  6. Ejecutando las pruebas que se encontraron.

  7. Destruyendo las bases de datos de prueba.

  8. Realizando el desmantelamiento global posterior a la prueba.

Si defines tu propia clase de ejecución de pruebas y apuntas TEST_RUNNER hacia esa clase, Django ejecutará tu ejecutor de pruebas cada vez que ejecutes ./manage.py test. De esta manera es posible utilizar cualquier framework de pruebas que pueda ser ejecutado desde código Python o modificar el proceso de ejecución de pruebas de Django para satisfacer las necesidades de prueba que puedas tener.

Definir un ejecutor de pruebas

Un ejecutor de pruebas es una clase que define un método run_tests(). Django incluye la clase DiscoverRunner que define el comportamiento de testing por defecto de Django. Esta clase define el punto de entrada run_tests(), más algunos otros métodos utilizados por run_tests() para configurar, ejecutar y desmantelar el conjunto de pruebas.

class DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, parallel=0, tags=None, exclude_tags=None, test_name_patterns=None, pdb=False, buffer=False, enable_faulthandler=True, timing=True, shuffle=False, logger=None, durations=None, **kwargs)[fuente]

DiscoverRunner buscará pruebas en cualquier archivo que coincida con pattern.

Puedes utilizar top_level para especificar el directorio que contiene tus módulos Python de nivel superior. Normalmente, Django puede determinarlo automáticamente, por lo que no es necesario especificarlo. Si se especifica, debe ser generalmente el directorio que contiene tu archivo manage.py.

verbosity determina la cantidad de notificación e información de depuración que se imprimirá en la consola; 0 es sin salida, 1 es la salida normal y 2 es la salida detallada.

Si interactive es True, el conjunto de pruebas tiene permiso para preguntar al usuario instrucciones cuando se ejecuta el conjunto de pruebas. Un ejemplo de este comportamiento sería preguntar permiso para eliminar una base de datos de prueba existente. Si interactive es False, el conjunto de pruebas debe poder ejecutarse sin ninguna intervención manual.

Si failfast es True, el conjunto de pruebas se detendrá después de que se detecte la primera falla de prueba.

Si keepdb es True, el conjunto de pruebas utilizará la base de datos existente, o creará una si es necesario. Si False, se creará una nueva base de datos, solicitando al usuario que elimine la existente, si está presente.

Si reverse es True, los casos de prueba se ejecutarán en el orden opuesto. Esto podría ser útil para depurar pruebas que no están aisladas correctamente y tienen efectos laterales. Grupos por clase de test se preservan cuando se utiliza esta opción. Esta opción puede usarse conjuntamente con --shuffle para revertir el orden para una semilla aleatoria en particular.

debug_mode especifica qué debe ser la configuración DEBUG antes de ejecutar las pruebas.

parallel especifica el número de procesos. Si parallel es mayor que 1, el conjunto de pruebas se ejecutará en procesos paralelos. Si hay menos clases de casos de prueba que configuraciones de procesos, Django reducirá el número de procesos según corresponda. Cada proceso tiene su propia base de datos. Esta opción requiere la tercera parte del paquete tblib para mostrar las trazas de error correctamente.

tags se puede utilizar para especificar un conjunto de etiquetas para filtrar pruebas. Puede combinarse con exclude_tags.

exclude_tags se puede utilizar para especificar un conjunto de etiquetas para excluir pruebas. Puede combinarse con tags.

Si debug_sql es True, los casos de prueba fallidos mostrarán consultas SQL registradas en el logger de bases de datos django así como la traza de error. Si verbosity es 2, entonces se muestran las consultas en todos los tests.

test_name_patterns se puede utilizar para especificar un conjunto de patrones para filtrar métodos y clases de prueba por sus nombres.

Si pdb es True, se lanzará un depurador (pdb o ipdb) en cada error o falla de prueba.

Si buffer es True, se descartarán los resultados de las pruebas pasadas.

Si enable_faulthandler es True, se habilitará faulthandler.

Si timing es True, se mostrarán los tiempos de prueba, incluyendo la configuración de la base de datos y el tiempo total de ejecución.

Si shuffle es un entero, las pruebas se mezclarán en un orden aleatorio antes de su ejecución, utilizando el entero como semilla aleatoria. Si shuffle es None, se generará la semilla aleatoriamente. En ambos casos, la semilla se registrará y se establecerá en self.shuffle_seed antes de ejecutar las pruebas. Esta opción se puede utilizar para ayudar a detectar pruebas que no están correctamente aisladas. Se preserva el orden por clase de prueba <order-of-tests> cuando se utiliza esta opción.

logger se puede utilizar para pasar un objeto Logger de Python. Si se proporciona, el logger se usará para registrar mensajes en lugar de imprimirlos en la consola. El objeto del logger respetará su nivel de registro en lugar de verbosity.

durations mostrará una lista de las N pruebas más lentas. Establecer esta opción en 0 resultará en que se muestren los tiempos de ejecución para todas las pruebas. Requiere Python 3.12+.

Django puede ampliar ocasionalmente las capacidades del ejecutor de pruebas agregando nuevos argumentos. La declaración **kwargs permite esta expansión. Si se subclasa DiscoverRunner o se escribe un propio ejecutor de pruebas, asegúrese de que acepte **kwargs.

Tu ejecutor de pruebas también puede definir opciones de línea de comandos adicionales. Crea o sobreescriba el método de clase add_arguments(cls, parser) y agrega argumentos personalizados llamando a parser.add_argument() dentro del método, para que la test comando pueda utilizar esos argumentos.

Atributos

DiscoverRunner.test_suite

La clase utilizada para construir el conjunto de pruebas. Por defecto se establece en unittest.TestSuite. Esto se puede sobrescribir si desea implementar lógica diferente para recopilar pruebas.

DiscoverRunner.test_runner

This is the class of the low-level test runner which is used to execute the individual tests and format the results. By default it is set to unittest.TextTestRunner. Despite the unfortunate similarity in naming conventions, this is not the same type of class as DiscoverRunner, which covers a broader set of responsibilities. You can override this attribute to modify the way tests are run and reported.

DiscoverRunner.test_loader

Esta es la clase que carga los tests, ya sea desde TestCases o módulos o de otra forma y los agrupa en conjuntos de pruebas para que el ejecutor pueda ejecutarlos. Por defecto está configurado con unittest.defaultTestLoader. Puedes sobrescribir este atributo si tus tests van a ser cargados de manera inusual.

Métodos

DiscoverRunner.run_tests(test_labels, **kwargs)[fuente]

Ejecuta el conjunto de pruebas.

test_labels te permite especificar qué tests ejecutar y admite varios formatos (consulte DiscoverRunner.build_suite() para obtener una lista de los formatos admitidos).

Este método debe devolver el número de tests que fallaron.

classmethod DiscoverRunner.add_arguments(parser)[fuente]

Sobrescribe este método de clase para agregar argumentos personalizados aceptados por la orden de comando de administración test. Consulte argparse.ArgumentParser.add_argument() para obtener detalles sobre cómo agregar argumentos a un parser.

DiscoverRunner.setup_test_environment(**kwargs)[fuente]

Configura el entorno de prueba llamando a setup_test_environment() y estableciendo DEBUG en self.debug_mode (por defecto es False).

DiscoverRunner.build_suite(test_labels=None, **kwargs)[fuente]

Construye un conjunto de pruebas que coincida con las etiquetas de la prueba proporcionadas.

test_labels es una lista de cadenas que describen las pruebas a ejecutar. Una etiqueta de prueba puede tomar una de cuatro formas:

  • path.to.test_module.TestCase.test_method – Ejecuta un método de prueba individual en una clase de casos de prueba.

  • path.to.test_module.TestCase – Ejecuta todos los métodos de prueba en un caso de prueba.

  • path.to.module – Busca y ejecuta todos los tests en el paquete o módulo Python especificado.

  • path/to/directory – Busca y ejecuta todos los tests debajo del directorio especificado.

Si test_labels tiene un valor de None, el ejecutor de pruebas buscará tests en todos los archivos debajo del directorio actual cuyos nombres coincidan con su pattern (consulte arriba).

Devuelve una instancia de TestSuite lista para ser ejecutada.

DiscoverRunner.setup_databases(**kwargs)[fuente]

Crea las bases de datos de prueba llamando a setup_databases().

DiscoverRunner.run_checks(databases)[fuente]

Ejecuta los controles del sistema en las bases de datos de prueba.

DiscoverRunner.run_suite(suite, **kwargs)[fuente]

Ejecuta la suite de pruebas.

Devuelve el resultado producido por la ejecución de la suite de pruebas.

DiscoverRunner.get_test_runner_kwargs()[fuente]

Returns the argumentos de palabra clave para instanciar el DiscoverRunner.test_runner con.

DiscoverRunner.teardown_databases(old_config, **kwargs)[fuente]

Destruye las bases de datos de prueba, restaurando las condiciones pre-test por llamada a teardown_databases().

DiscoverRunner.teardown_test_environment(**kwargs)[fuente]

Restaura el entorno pre-test.

DiscoverRunner.suite_result(suite, result, **kwargs)[fuente]

Computa y devuelve un código de retorno basado en un conjunto de pruebas, y el resultado de ese conjunto de pruebas.

DiscoverRunner.log(msg, level=None)[fuente]

Si se establece logger, registra el mensaje con el nivel de registro dado (logging level (por ejemplo, logging.DEBUG, logging.INFO o logging.WARNING)). De lo contrario, el mensaje se imprime en la consola, respetando la actualidad verbosity. Por ejemplo, no se imprimirá ningún mensaje si la verbosity es 0, se imprimirán mensajes de INFO y por encima si la verbosity es al menos 1, y se imprimirá DEBUG si es al menos 2. El nivel predeterminado es logging.INFO.

Utilidades de prueba

django.test.utils

Para ayudar en la creación de su propio ejecutor de pruebas, Django proporciona una serie de métodos de utilidad en el módulo django.test.utils.

setup_test_environment(debug=None)[fuente]

Realiza la configuración pre-test global, como instalar instrumentaciones para el sistema de renderizado de plantillas y configurar la caja de salida de correo electrónico dummy.

Si debug no es None, se actualiza el valor de la configuración DEBUG.

teardown_test_environment()[fuente]

Ejecuta la desmontaje global posterior a las pruebas, como eliminar instrumentación del sistema de plantillas y restaurar los servicios de correo electrónico normales.

setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, debug_sql=False, parallel=0, aliases=None, serialized_aliases=None, **kwargs)[fuente]

Crea las bases de datos de prueba.

Devuelve una estructura de datos que proporciona suficiente detalle para deshacer los cambios realizados. Esta información se le pasará a la función teardown_databases() al finalizar las pruebas.

La argumento aliases determina qué alias de bases de datos (DATABASES) deben configurarse para las bases de datos de prueba. Si no se proporciona, utiliza todos los alias de bases de datos (DATABASES).

La argumento serialized_aliases determina qué subconjunto de aliases las bases de datos de prueba deben tener su estado serializado para permitir el uso de la característica serialized_rollback. Si no se proporciona, se establece por defecto en aliases.

teardown_databases(old_config, parallel=0, keepdb=False)[fuente]

Destruye las bases de datos de prueba, restaurando las condiciones previas a la prueba.

old_config es una estructura de datos que define los cambios en la configuración del servidor de bases de datos que deben ser revertidos. Es el valor de retorno del método setup_databases().

django.db.connection.creation

La creación del módulo de la base de datos también proporciona algunas utilidades que pueden ser útiles durante las pruebas.

create_test_db(verbosity=1, autoclobber=False, serialize=True, keepdb=False)

Crea una nueva base de datos de prueba y ejecuta migrate contra ella.

La traducción de los textos es la siguiente:

autoclobber describe el comportamiento que ocurrirá si se descubre una base de datos con el mismo nombre que la base de datos de prueba:

  • Si autoclobber es False, al usuario se le pedirá que apruebe la destrucción de la base de datos existente. Se llama a sys.exit si el usuario no aprueba.

  • Si autoclobber es True, la base de datos se destruirá sin consultar al usuario.

serialize determina si Django serializa la base de datos en una cadena JSON en memoria antes de ejecutar las pruebas (utilizada para restaurar el estado de la base de datos entre pruebas si no tienes transacciones). Puedes establecer esto en False para acelerar el tiempo de creación si no tienes ninguna clase de prueba con serialized_rollback=True.

keepdb determina si la ejecución de pruebas debe utilizar una base de datos existente o crear una nueva. Si True, se utilizará la base de datos existente, o se creará si no está presente. Si False, se creará una nueva base de datos, pidiendo al usuario que elimine la existente, si está presente.

Devuelve el nombre de la base de datos de prueba que creó.

create_test_db() tiene el efecto secundario de modificar el valor de NAME en DATABASES para coincidir con el nombre de la base de datos de prueba.

destroy_test_db(old_database_name, verbosity=1, keepdb=False)

Destruye la base de datos cuyo nombre es el valor de NAME en DATABASES, y establece NAME en el valor de old_database_name.

El argumento verbosity tiene el mismo comportamiento que para DiscoverRunner.

Si el argumento keepdb es True, entonces la conexión a la base de datos se cerrará, pero la base de datos no será destruida.

serialize_db_to_string()

Serializa la base de datos en una cadena JSON en memoria que puede utilizarse para restaurar el estado de la base de datos entre pruebas si el backend no admite transacciones o si tu suite contiene clases de prueba con serialized_rollback=True habilitadas.

Esta función solo debe llamarse una vez que todas las bases de datos de prueba hayan sido creadas, ya que el proceso de serialización podría dar lugar a consultas contra bases de datos no de prueba dependiendo de tu configuración de enrutado.

Integración con coverage.py

La cobertura de código describe cuánto código fuente se ha probado. Muestra qué partes de tu código están siendo ejecutadas por las pruebas y cuáles no. Es una parte importante de probar aplicaciones, por lo que se recomienda encarecidamente comprobar la cobertura de tus pruebas.

Django puede integrarse fácilmente con coverage.py_, una herramienta para medir la cobertura del código de programas Python. Primero, instala coverage. A continuación, ejecuta lo siguiente desde tu carpeta de proyecto que contenga manage.py:

coverage run --source='.' manage.py test myapp

Esto ejecuta tus pruebas y recopila datos de cobertura de los archivos ejecutados en tu proyecto. Puedes ver un informe de estos datos escribiendo el comando siguiente:

coverage report

Ten en cuenta que se ejecutó código Django mientras se corrían las pruebas, pero no está incluido aquí debido a la bandera source pasada al comando anterior.

Para más opciones como listados HTML anotados con detalles de líneas faltantes, consulta los docs de coverage.py_.