Falta una tabla al ejecutar Django Unittest con Sqlite3

Estoy tratando de hacer una prueba de unidad con Django 1.3. Normalmente, uso MySQL como base de datos de mi base de datos, pero como esto es muy lento para girar en una sola prueba de unidad, estoy usando Sqlite3.

Así que para cambiar a Sqlite3 solo para mis pruebas de unidad, en mi configuración.py tengo:

import sys if 'test' in sys.argv: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME':'/tmp/database.db', 'USER' : '', 'PASSWORD' : '', 'HOST' : '', } } 

Cuando ejecuto mi python manage.py test myapp.Test.test_myfunc con python manage.py test myapp.Test.test_myfunc , python manage.py test myapp.Test.test_myfunc el error:

 DatabaseError: no such table: django_content_type 

Google muestra que hay algunos motivos posibles para este error , ninguno de los cuales me parece aplicable. No estoy ejecutando Apache, así que no veo cómo los permisos serían un problema. El archivo /tmp/database.db se está creando, por lo que / tmp se puede escribir. La aplicación django.contrib.contenttypes está incluida en mi INSTALLED_APPS.

¿Qué me estoy perdiendo?

Edit: Me encontré con este problema nuevamente en Django 1.5, pero ninguna de las soluciones propuestas funciona.

Related of "Falta una tabla al ejecutar Django Unittest con Sqlite3"

En Django 1.4, 1.5, 1.6, 1.7 o 1.8 debería ser suficiente para usar:

 if 'test' in sys.argv: DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3' 

No debería ser necesario anular TEST_NAME 1 , ni llamar a syncdb para ejecutar pruebas. Como @osa señala, el valor predeterminado con el motor SQLite es crear la base de datos de prueba en la memoria ( TEST_NAME=':memory:' ). Llamar a syncdb no debería ser necesario porque el marco de prueba de Django lo hará automáticamente a través de una llamada a syncdb o migrate según la versión de Django. 2 Puede observar esto con manage.py test -v [2|3] .

En términos generales, Django configura el entorno de prueba de la siguiente manera:

  1. Cargando el nombre de la base de datos regular desde su settings.py
  2. Descubrir y construir sus clases de prueba (se __init__() )
  3. Configurando la base de datos NAME al valor de TEST_NAME
  4. Ejecutando las pruebas contra la base de datos NAME

Aquí está el problema: en el paso 2, NAME sigue apuntando a su base de datos regular (no de prueba). Si sus pruebas contienen consultas de nivel de clase o consultas en __init__() , se ejecutarán en la base de datos regular, que probablemente no sea lo que está esperando. Esto se identifica en el bug # 21143 .

No hagas

 class BadFooTests(TestCase): Foo.objects.all().delete() # <-- class level queries, and def __init__(self): f = Foo.objects.create() # <-- queries in constructor f.save() # will run against the production DB def test_foo(self): # assert stuff 

ya que estos se ejecutarán contra la base de datos especificada en NAME . Si NAME en esta etapa apunta a una base de datos válida (por ejemplo, su base de datos de producción), la consulta se ejecutará, pero puede tener consecuencias no deseadas. Si ha reemplazado ENGINE y / o NAME modo que no apunte a una base de datos preexistente, se lanzará una excepción porque aún no se ha creado la base de datos de prueba:

 django.db.utils.DatabaseError: no such table: yourapp_foo # Django 1.4 DatabaseError: no such table: yourapp_foo # Django 1.5 OperationalError: no such table: yourapp_foo # Django 1.6+ 

En su lugar haz:

 class GoodFooTests(TestCase): def setUp(self): f = Foo.objects.create() # <-- will run against the test DB f.save() # def test_foo(self): # assert stuff 

Por lo tanto, si observa errores, verifique que sus pruebas no incluyan ninguna consulta que pueda afectar a la base de datos fuera de las definiciones de métodos de clase de prueba.


[1] En Django> = 1.7, DATABASES[alias]['TEST_NAME'] está en desuso a favor de DATABASES[alias]['TEST']['NAME']
[2] Ver el método create_test_db() en db/backends/creation.py

Yo tuve este problema también. Resultó que tenía que agregar una propiedad TEST_NAME en el archivo settings.py para identificar la base de datos de prueba correctamente. Me solucionó el problema:

 if 'test' in sys.argv: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(os.path.dirname(__file__), 'test.db'), 'TEST_NAME': os.path.join(os.path.dirname(__file__), 'test.db'), } } 

Solo para agregar otro caso a esto:

Si está intentando actualizar a 1.8 desde 1.6 (o desde una configuración que no es de migración a una configuración de migración), puede llegar a este error si no ha ejecutado las migraciones creadas.

Tuve el mismo problema y tuve que crear migraciones para que el corredor de pruebas pudiera usarlas, lo cual no era intuitivo porque antes de las migraciones, las pruebas solo harían una nueva base de datos basada en syncdb, que siempre funcionaba.

Habiendo probado todo lo anterior, eventualmente descubrí otra razón por la que esto puede suceder:

Si alguno de sus modelos no es creado por una de sus migraciones.

Hice algo de depuración y parece que las pruebas de Django configuran la base de datos aplicando todas sus migraciones en orden, comenzando con 001_initial.py , antes de intentar SELECCIONAR de las tablas basadas en sus modelos.py

En mi caso, de alguna manera no se había agregado una tabla a las migraciones, sino que se agregó manualmente, por lo que no se pudo aplicar correctamente el conjunto de migración completo. Cuando arreglé manualmente la migración 001_initial.py para crear esta tabla, el error operacional desapareció.

Para futuras referencias, esto también sucede si su aplicación no se agrega a su INSTALLED_APPS , por ejemplo:

 INSTALLED_APPS = ( ... 'myapp' ) 

De lo contrario obtendrás

 OperationalError: no such table: myapp_mytable 

Su base de datos probablemente esté vacía, debe configurarse con todas las tablas correspondientes a sus modelos. Normalmente, esto se haría ejecutando python manage.py syncdb primero, para crear todas las tablas de su base de datos. El problema es que, en su caso, cuando ejecuta syncdb, python no verá que está ejecutando una prueba, por lo que intentará configurar tablas en su base de datos MySQL.

Para evitar esto, cambiar temporalmente

 if 'test' in sys.argv: 

a

 if True: 

Luego ejecute python manage.py syncdb para configurar las tablas de la base de datos sqlite. Ahora que todo está configurado, puede volver a ponerlo if 'test'... y todo debería funcionar sin problemas. Sin embargo, es probable que desee mover su base de datos fuera del directorio /tmp : django necesita reutilizar la misma base de datos cada vez que ejecute sus pruebas; de lo contrario, tendrá que crear tablas de bases de datos antes de cada prueba.

Tenga en cuenta que si agrega nuevos modelos, deberá repetir este procedimiento para crear las nuevas tablas en sqlite. Si agrega campos nuevos a un modelo existente, deberá agregar columnas manualmente a su base de datos sqlite usando la interfaz sqlite y ALTER TABLE... , o hacerlo automáticamente usando una herramienta como South.

Tuve que agregar las siguientes líneas después de la definición de la base de datos de prueba:

 from django.core.management import call_command call_command('syncdb', migrate=True) 

Tuve un problema similar y fui causado por un código de sucursal anterior, así que lo arreglé eliminando los archivos pyc en mis proyectos:

 find -regex .*pyc | xargs sudo rm 

Hay muchas razones por las que este error puede ocurrir, para mí tenía que ver con migraciones de datos piratas.

Estas migraciones de datos realizaron algunas operaciones en un modelo que requería un campo que aún no se había creado.

P.ej

 0001_accounts.py {create the model User} 0002_accounts.py {{for user in User.objects.all(): user.save() } 0003_accounts.py {add a new column to User object} 

Falla en 0002 cuando intenta guardar el objeto de usuario pero aún no tiene la nueva columna.

Depurar:

 switch to an empty database run python manage.py migrate 

Vea dónde se detiene, es probable que esa sea la visita de datos de hackers que querría descomentar.

Para aquellos que intentaron todas las formas posibles pero que siguen atrapados en esto:

Dado que nuestro código de prueba todavía se está ejecutando en otra máquina pero no en la mía, intenté:

  • Crea una nueva env. Virtual. (aislar así el efecto de las aplicaciones)
  • Clona un nuevo repository. (aislar el efecto de los archivos ignorados)
  • Establecer en la settings para usar sqlite3 lugar de psql (aislar el efecto de la base de datos y la configuración de la base de datos)
  • Verifique las variables env y el archivo .env (ya que utilicé el foreman )

Ninguno de esos ayudó. Hasta que yo:

  1. Crear una nueva cuenta en mi máquina. (Así que empieza limpio)
  2. Clona el repository.
  3. Ejecutar pruebas -> Éxito 😑
  4. Vuelve a mi cuenta principal.
  5. Abra una nueva terminal ( tmux servidor tmux actual si los está utilizando).
  6. Ejecutar pruebas -> Éxito 😯

Entonces, esta no es una respuesta real para su pregunta, ya que no sé qué estuvo mal y cómo se solucionó, solo otra sugerencia que puede intentar.

Para cualquiera que llegue aquí, busque por qué Django sigue creando una base de datos independientemente de la opción --keepdb . ¿Por qué dice Using existing test database for alias 'default' , pero luego ejecuta un montón de instrucciones CREATE TABLE .

Si no establece una configuración de BASE DE DATOS> predeterminada> PRUEBA> NOMBRE , Django intentará usar en la base de datos de memoria y no se mantendrá, así que establezca esto y anule los valores predeterminados.

Puedes hacerlo así:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(ROOT_DIR, 'data', 'db.dev.sqlite3'), 'TEST': { 'NAME': os.path.join(ROOT_DIR, 'data', 'db.test.sqlite3'), } } }