Je crois savoir que MagicMock est un sur-ensemble de Mock qui fait automatiquement des "méthodes magiques", fournissant ainsi un support transparent pour les listes, les itérations, etc... Alors quelle est la raison d'être de Mock existant ? Est-ce que ce n'est pas juste une version dépouillée de MagicMock que l'on peut pratiquement ignorer ? Est-ce que Mock classe connaissent des astuces qui ne sont pas disponibles dans MagicMock ?
Réponses
Trop de publicités?Quelle est la raison de l'unification Mock existant ?
L'auteur de Mock, Michael Foord, s'est adressé à une question très similaire à Pycon 2011 (31:00) :
Q : Pourquoi MagicMock a-t-il été créé séparément au lieu de simplement intégrer cette capacité dans l'objet fantaisie par défaut ?
A : 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 paramétrant. et en les paramétrant, donc si chaque nouveau mock créait un tas de nouveaux mocks et et les définissait comme des méthodes de protocole, puis toutes ces méthodes de protocole créaient un tas d'autres mocks et les définissaient sur leurs méthodes de protocole, vous avez une récursion infinie ...
Et si vous voulez que l'accès à votre objet fantaisie en tant qu'objet de conteneur soit un erreur - vous ne voulez pas que cela fonctionne ? Si chaque mock a automatiquement obtenu chaque méthode de protocole, alors il devient beaucoup plus difficile de faire cela. Et aussi, MagicMock fait une partie de cette préconfiguration pour vous, en fixant des valeurs de retour qui pourraient ne pas être appropriées, donc j'ai pensé qu'il qu'il serait mieux d'avoir cette méthode pratique qui a tout préconfiguré et disponible pour vous, mais vous pouvez également prendre un objet ordinaire ordinaire et juste configurer les méthodes magiques que vous voulez voir exister...
La réponse simple est la suivante : utilisez MagicMock partout si c'est le comportement que vous souhaitez.
Avec Mock you peut des méthodes magiques de moquerie, 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 un grand nombre de méthodes magiques, MagicMock vous fera gagner du temps.
Pour commencer, MagicMock
est une sous-classe de Mock
.
class MagicMock(MagicMixin, Mock)
Par conséquent, 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, considérez MagicMock comme une version étendue de Mock. Cela devrait répondre à vos questions sur la raison d'être 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 des méthodes magiques, alors que Mock ne le fait pas. Voir aquí pour plus d'informations sur les méthodes magiques proposées.
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 celles qui ne sont peut-être pas aussi intuitives (du moins pas 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 invoqué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 par défaut de la méthode magique ? Par exemple, est-il acceptable que mocked_object[1]
pour ne pas faire d'erreur ? Êtes-vous d'accord avec d'éventuelles conséquences involontaires dues à l'existence des implémentations de la méthode magique ?
Si la réponse à ces questions est un oui, alors allez-y et utilisez MagicMock. Sinon, restez-en à Mock.
C'est ce que la 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 performante, il est judicieux de l'utiliser par défaut.
J'ai trouvé un autre cas particulier où simple Mock
peut s'avérer 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
Comparaison avec ANY
peut être utile, par exemple, pour comparer presque chaque clé entre deux dictionnaires où une valeur est calculée à l'aide d'un simulateur.
Cela sera valable si vous utilisez Mock
:
self.assertDictEqual(my_dict, {
'hello': 'world',
'another': ANY
})
alors qu'il soulèvera un AssertionError
si vous avez utilisé MagicMock