web-dev-qa-db-fra.com

Mock vs MagicMock

Je crois comprendre que MagicMock est un sur-ensemble de Mock qui exécute automatiquement des "méthodes magiques", fournissant ainsi un support transparent pour les listes, les itérations, etc. ... Quelle en est la raison pour plain Mock existant? N’est-ce pas une version simplifiée de MagicMock qui peut être pratiquement ignorée? La classe Mock connaît-elle des astuces qui ne sont pas disponibles dans MagicMock?

122
Vladimir Ignatov

Quelle est la raison de plain Mock existant?

L'auteur de Mock, Michael Foord, s'est adressé à ne 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 fictif par défaut?

R: Une réponse raisonnable est que MagicMock fonctionne de manière à préconfigurer toutes ces méthodes de protocole en créant de nouveaux Mock et en les définissant, donc si chaque nouveau mock créé un groupe de nouveaux modèles et les a définis comme méthodes de protocole, puis toutes ces méthodes de protocole ont créé un ensemble plus de modèles et les ont configurés sur leurs méthodes de protocole, vous obtenez une récursion 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 modèle a automatiquement toutes les méthodes de protocole, il devient 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, aussi j’ai pensé qu’il serait préférable d’avoir cette commodité qui contient tout ce qui est préconfiguré et disponible, mais vous pouvez également prendre une maquette ordinaire. objet et juste configurer les méthodes magiques que vous voulez exister ...

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

90
Ryne Everett

Avec Mock, vous pouvez simuler des méthodes magiques mais vous devez les définir. MagicMock a "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 suffisant et n'apporte pas beaucoup d'éléments étrangers à vos tests. Si vous devez tester de nombreuses méthodes magiques, MagicMock vous fera gagner du temps.

48
Sean Redmond

Pour commencer, MagicMock est 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 simplifiée de MagicMock, considérez MagicMock comme une version étendue de Mock. Cela devrait permettre de répondre à vos questions sur les raisons de l’existence de Mock et sur ce que Mock fournit en plus de MagicMock.

Deuxièmement, MagicMock fournit des implémentations par défaut de la plupart/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 est posée est la suivante: êtes-vous d'accord avec les implémentations de la méthode magique par défaut? Par exemple, est-ce que ça va pour mocked_object[1] ne pas se tromper? Acceptez-vous des conséquences inattendues dues aux implémentations de méthodes magiques déjà présentes?

Si la réponse à ces questions est affirmative, utilisez MagicMock. Sinon, restez fidèle à Mock.

40
user650654

C'est ce que documentation officielle de python dit:

Dans la plupart de ces exemples, les classes Mock et MagicMock sont interchangeables. Comme MagicMock est la classe la plus capable, il est judicieux de l'utiliser par défaut.

10
user2916464

J'ai trouvé un autre cas particulier où simpleMock 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 ANY peut être utile, par exemple, en comparant presque chaque clé entre deux dictionnaires pour lesquels une valeur est calculée à l'aide d'une fausse maquette.

Cela sera valable si vous utilisez Mock:


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

alors que cela déclenchera un AssertionError si vous avez utilisé MagicMock

1
Manu