Mock vs MagicMock

138

Je crois comprendre que MagicMock est un surensemble de Mock qui fait automatiquement « méthodes magiques » fournissant ainsi de façon transparente pour le soutien des listes, des itérations et ainsi de suite ... Quelle est donc la raison de plaine Mock existante? N'est-ce pas juste une version allégée de MagicMock qui peut être pratiquement ignorée? La classe Mock connaît-elle des astuces qui ne sont pas disponibles dans MagicMock ?

Vladimir Ignatov
la source

Réponses:

99

Quelle est la raison de l' existence de plain Mock ?

L'auteur de Mock, Michael Foord, a répondu à une question très similaire à Pycon 2011 (31:00) :

Q: Pourquoi MagicMock a-t-il été créé séparément plutôt que de simplement replier la capacité dans l'objet simulé par défaut?

R: Une réponse raisonnable est que la façon dont MagicMock fonctionne est qu'il préconfigure toutes ces méthodes de protocole en créant de nouveaux Mocks et en les définissant, donc si chaque nouveau Mock crée un tas de nouveaux Mocks et les définit comme méthodes de protocole, puis tous ces protocoles Les méthodes ont créé un tas d'autres simulations et les définissent sur leurs méthodes de protocole, vous avez une récursivité infinie ...

Que faire si vous voulez que l'accès à votre maquette en tant qu'objet conteneur soit une erreur - vous ne voulez pas que cela fonctionne? Si chaque maquette a automatiquement toutes les méthodes de protocole, il devient alors beaucoup plus difficile de le faire. Et aussi, MagicMock fait une partie de cette préconfiguration pour vous, définissant des valeurs de retour qui pourraient ne pas être appropriées, alors j'ai pensé qu'il serait préférable d'avoir cette commodité qui a tout préconfiguré et disponible pour vous, mais vous pouvez également prendre une simulation ordinaire objet et configurez simplement les méthodes magiques que vous voulez faire exister ...

La réponse simple est: utilisez simplement MagicMock partout si c'est le comportement que vous souhaitez.

Ryne Everett
la source
12
Je pense qu'une meilleure réponse est: utilisez MagicMock si vous savez ce que vous faites, sinon utilisez Mock.
laike9m
56

Avec Mock, vous pouvez vous moquer des méthodes magiques mais vous devez les définir. MagicMock a «des implémentations par défaut de la plupart des méthodes magiques». .

Si vous n'avez pas besoin de tester de méthodes magiques, Mock est adéquat et n'apporte pas beaucoup de choses étrangères dans vos tests. Si vous avez besoin de tester de nombreuses méthodes magiques, MagicMock vous fera gagner du temps.

Sean Redmond
la source
Effectivement, j'ai déjà lu la documentation. Cela ne répond pas à ma question - pourquoi s'embêter avec un simple Mock si MagicMock fait exactement la même chose et bien plus encore? Je ne vois aucune chose étrangère dans mes tests - utilisez simplement le nom différent et c'est tout. Alors, où est le piège?
Vladimir Ignatov
39
Les tests doivent être minimaux et les objets factices doivent être fonctionnels de manière minimale afin que vous soyez sûr exactement de ce que vous testez. Si vous utilisez MagicMock simplement parce qu'il fait plus mais que vous ne testez pas explicitement tout ce "plus", vous courez le risque d'un échec du test à cause d'un comportement par défaut de MagicMock. Cet échec pourrait refléter quelque chose sur les valeurs par défaut de MagicMock plus que ce qu'il est censé se moquer. Pire encore, vous courez le risque qu'un test réussisse alors qu'il aurait dû échouer. Le risque est faible, mais si cela se produit, cela vous fera perdre beaucoup de temps.
Sean Redmond
1
J'y pense comme si vous utilisiez JS ou Jquery. Bien sûr, vous pouvez utiliser Jquery pour faire tout votre JS, mais dans certains cas, vous voulez simplement utiliser l'outil le plus petit requis pour faire le travail. Je trouve que ces cas sont généralement extrêmement simples ou extrêmement complexes.
blottit
49

Pour commencer, MagicMockest une sous-classe de Mock.

class MagicMock(MagicMixin, Mock)

En conséquence, MagicMock fournit tout ce que Mock fournit et plus encore. Plutôt que de considérer Mock comme une version allégée de MagicMock, pensez à MagicMock comme une version étendue de Mock. Cela devrait répondre à vos questions sur la raison pour laquelle Mock existe et ce que Mock fournit en plus de MagicMock.

Deuxièmement, MagicMock fournit des implémentations par défaut de la plupart des méthodes magiques, contrairement à Mock. Voir ici pour plus d'informations sur les méthodes magiques fournies.

Quelques exemples de méthodes magiques fournies:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

Et ceux qui peuvent ne pas être aussi intuitifs (du moins pas intuitifs pour moi):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

Vous pouvez "voir" les méthodes ajoutées à MagicMock lorsque ces méthodes sont appelées pour la première fois:

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

Alors, pourquoi ne pas utiliser MagicMock tout le temps?

La question qui vous revient est la suivante: êtes-vous d'accord avec les implémentations de méthode magique par défaut? Par exemple, est-ce normal mocked_object[1]de ne pas se tromper? Êtes-vous d'accord avec les conséquences imprévues dues aux implémentations de méthodes magiques déjà présentes?

Si la réponse à ces questions est oui, alors allez-y et utilisez MagicMock. Sinon, restez fidèle à Mock.

user650654
la source
12

Voici ce que dit la documentation officielle de python :

Dans la plupart de ces exemples, les classes Mock et MagicMock sont interchangeables. Comme MagicMock est la classe la plus performante, il en fait une classe sensée à utiliser par défaut.

user2916464
la source
3

J'ai trouvé un autre cas particulier où le simple Mock peut devenir plus utile que MagicMock:

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

La comparaison avec ANYpeut être utile, par exemple, comparer presque toutes les clés entre deux dictionnaires où une valeur est calculée à l'aide d'un simulacre.

Cela sera valable si vous utilisez Mock:


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

alors qu'il soulèvera un AssertionErrorsi vous avez utiliséMagicMock

Manu
la source