python - queryset - group by django
Burlarse de un Django Queryset para probar una función que toma un queryset (7)
Tengo una función de utilidad en mi proyecto Django, toma un queryset, obtiene algunos datos de él y devuelve un resultado. Me gustaría escribir algunas pruebas para esta función. ¿Hay alguna forma de "burlarse" de un QuerySet? Me gustaría crear un objeto que no toque la base de datos, y puedo proporcionarle una lista de valores para usar (es decir, algunas filas falsas) y luego actuará como un queryset, y permitirá que alguien pueda hacer búsquedas de campo en él / filtrar / obtener / todo etc.
¿Ya existe algo como esto?
Estoy teniendo el mismo problema, y parece que una buena persona ha escrito una biblioteca para burlarse de QuerySets, se llama mock-django y el código específico que necesitará está aquí https://github.com/dcramer/mock-django/blob/master/mock_django/query.py ¡Creo que luego puede parchear la función de los modelos de objetos para devolver uno de estos objetos QuerySetMock que ha configurado para devolver algo esperado!
No que yo sepa, pero ¿por qué no usar un queryset real? El marco de prueba está configurado para permitirle crear datos de muestra dentro de su prueba, y la base de datos se vuelve a crear en cada prueba, por lo que no parece haber ninguna razón para no usar el objeto real.
Para esto uso la función .none () de Django .
Por ejemplo:
class Location(models.Model):
name = models.CharField(max_length=100)
mock_locations = Location.objects.none()
Este es el método utilizado frecuentemente en los casos de prueba internos de Django. Basado en comentarios en el código.
Calling none() will create a queryset that never returns any objects and no
+query will be executed when accessing the results. A qs.none() queryset
+is an instance of ``EmptyQuerySet``.
Para un Queryset vacío, iría simplemente para usar none
como keithhackbarth ya ha indicado .
Sin embargo, para simular un Queryset que devolverá una lista de valores, prefiero usar un Mock con una spec
del administrador del modelo. Como ejemplo (estilo Python 2.7 - He usado la biblioteca de simulacros externa ), aquí hay una prueba simple donde se filtra el Queryset y luego se cuenta:
from django.test import TestCase
from mock import Mock
from .models import Example
def queryset_func(queryset, filter_value):
"""
An example function to be tested
"""
return queryset.filter(stuff=filter_value).count()
class TestQuerysetFunc(TestCase):
def test_happy(self):
"""
`queryset_func` filters provided queryset and counts result
"""
m_queryset = Mock(spec=Example.objects)
m_queryset.filter.return_value = m_queryset
m_queryset.count.return_value = 97
result = func_to_test(m_queryset, ''__TEST_VALUE__'')
self.assertEqual(result, 97)
m_queryset.filter.assert_called_once_with(stuff=''__TEST_VALUE__'')
m_queryset.count.assert_called_once_with()
Sin embargo, para cumplir con la pregunta, en lugar de establecer un valor de return_value
para el count
, esto podría ajustarse fácilmente para que sea una list
de instancias de modelo devueltas por all
.
Tenga en cuenta que el encadenamiento se maneja configurando el filter
para devolver el queryset simulado:
m_queryset.filter.return_value = m_queryset
Esto debería aplicarse a cualquier método de conjunto de consultas utilizado en la función bajo prueba, por ejemplo, exclude
, etc.
Por supuesto que puedes burlarte de un QuerySet, puedes burlarte de cualquier cosa.
Puede crear un objeto usted mismo, y darle la interfaz que necesita, y hacer que devuelva los datos que desee. En el fondo, la burla no es más que proporcionar un "doble de prueba" que actúa lo suficiente como para los propósitos de tus pruebas.
La forma de comenzar de baja tecnología es definir un objeto:
class MockQuerySet(object):
pass
luego crea uno de estos y entrégalo a tu prueba. La prueba fallará, probablemente en un AttributeError
. Eso le dirá lo que necesita implementar en su MockQuerySet
. Repita hasta que su objeto sea lo suficientemente rico para sus pruebas.
Pruebe la biblioteca django_mock_queries
que le permite django_mock_queries
el acceso a la base de datos y seguir utilizando algunas de las características del conjunto de consultas de Django, como el filtrado.
Revelación completa: aporté algunas características al proyecto.
Un primer consejo sería dividir la función en dos partes, una que crea el conjunto de consultas y otra que manipula la salida de la misma. De esta manera, probar la segunda parte es sencillo.
Para el problema de la base de datos, investigué si django usa sqlite-in-memory y descubrí que la versión reciente de django usa la base de datos sqlite -in-memory, de la página de prueba de django unit :
Cuando se usa el motor de base de datos SQLite, las pruebas usarán por defecto una base de datos en memoria (es decir, la base de datos se creará en la memoria, ¡evitando el sistema de archivos por completo!).
Simularse con el objeto QuerySet no hará que ejerza toda su lógica.