Se moquant D'un Queryset Django pour tester une fonction qui prend un queryset

j'ai une fonction d'utilité dans mon projet Django, il faut un queryset, obtient quelques données et renvoie un résultat. J'aimerais faire quelques tests pour cette fonction. Y a-t-il un moyen de "se moquer" d'un QuerySet? Je voudrais créer un objet qui ne touche pas la base de données, et je peux lui fournir une liste de valeurs à utiliser (i.e. quelques lignes de faux) et puis il agira comme un queryset, et permettra à quelqu'un de faire des recherches de champ sur elle/filtre/get/all etc.

fait quelque chose comme ça existent déjà?

25
demandé sur Rory 2011-09-09 18:10:42

7 réponses

Pas que je sache, mais pourquoi ne pas utiliser un réel queryset? Le cadre de test est tout mis en place pour vous permettre de créer des données d'échantillon dans votre test, et la base de données est recréée sur chaque test, donc il ne semble pas y avoir de raison de ne pas utiliser la chose réelle.

-5
répondu Daniel Roseman 2011-09-09 14:16:07

bien sûr, vous pouvez vous moquer d'un QuerySet, vous pouvez vous moquer de n'importe quoi.

vous pouvez créer un objet vous-même, et lui donner l'interface dont vous avez besoin, et lui faire retourner toutes les données que vous voulez. Au fond, se moquer n'est rien de plus que de fournir un "test double" qui agit assez comme la vraie chose pour les buts de vos tests.

la façon la moins technique de commencer est de définir un objet:

class MockQuerySet(object):
    pass

alors créez l'un de ceux-ci, et donnez-le à votre test. Le test échouera, probablement sur un AttributeError. Qui vous dira ce que vous devez mettre en œuvre sur votre MockQuerySet. Répétez jusqu'à ce que votre objet soit assez riche pour vos tests.

16
répondu Ned Batchelder 2018-05-22 20:44:05

je vais avoir le même problème, et il ressemble à la personne agréable a écrit une bibliothèque pour se moquant de QuerySets, il est appelé maquette-django et le code spécifique que vous aurez besoin est ici https://github.com/dcramer/mock-django/blob/master/mock_django/query.py je pense que vous pouvez ensuite simplement patch vous les modèles les objets de la fonction de retour de l'un de ces QuerySetMock les objets que vous avez mis en place pour revenir à quelque chose de prévu!

9
répondu Ctrlspc 2012-09-10 12:33:40

pour un Queryset vide, j'irais simplement pour utiliser nonekeithhackbarth a déjà déclaré.

Cependant, pour simuler un Queryset qui retournera une liste de valeurs, je préfère utiliser un Faux avec un spec du directeur du modèle. Comme exemple (Python 2.7 style - j'ai utilisé la bibliothèque simulée externe), voici un test simple où le Queryset est filtré puis compté:

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()

toutefois, pour remplir les conditions la question, au lieu de mettre un return_valuecount, ce qui pourrait facilement être ajusté à un list des instances de modèle retourné à partir de all.

notez que le chaînage est traité parfilter pour revenir à la moqué de queryset:

m_queryset.filter.return_value = m_queryset

ceci devrait être appliqué à toutes les méthodes queryset utilisées dans la fonction testée, par exemple exclude, etc.

6
répondu jamesc 2017-05-23 12:32:02

Pour cela, j'utilise Django .aucune fonction ().

Par exemple:

class Location(models.Model):
  name = models.CharField(max_length=100)
mock_locations = Location.objects.none()
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``.
2
répondu keithhackbarth 2016-03-15 15:16:24

Essayer django_mock_queries bibliothèque qui vous permet de vous moquer de l'accès à la base de données, et toujours utiliser certaines des fonctionnalités de l'ensemble de requête Django comme le filtrage.

divulgation complète: j'ai contribué à certaines fonctionnalités du projet.

0
répondu Don Kirkby 2018-05-12 00:35:39

Un premier conseil serait de diviser la fonction en deux parties, une qui crée le queryset et celui qui manipule la sortie. De cette façon, tester la deuxième partie est simple.

pour le problème de la base de données, j'ai cherché si django utilise sqlite-in-memory et j'ai découvert que la version récente de django utilise la base de données sqlite-in-memory, de django unittest page:

lors de l'utilisation du moteur de base de données SQLite utilisera par défaut un base de données en mémoire (c'est à dire, la base de données sera créée dans la mémoire, contourner entièrement le système de fichiers!).

se moquer de L'objet QuerySet ne vous fera pas exercer toute sa logique.

-1
répondu fabrizioM 2011-09-09 17:36:11