web-dev-qa-db-fra.com

Affirmer qu'une fonction/méthode n'a pas été appelée avec Mock

J'utilise la bibliothèque Mock pour tester mon application, mais je tiens à affirmer qu'aucune fonction n'a été appelée. Les documents factices évoquent des méthodes telles que mock.assert_called_with et mock.assert_called_once_with, mais je n'ai rien trouvé de tel que mock.assert_not_called ou quelque chose permettant de vérifier que la commande simulée était PAS appelé .

Je pourrais aller avec quelque chose comme ce qui suit, bien que cela ne semble pas cool ni Pythonic:

def test_something:
    # some actions
    with patch('something') as my_var:
        try:
            # args are not important. func should never be called in this test
            my_var.assert_called_with(some, args)
        except AssertionError:
            pass  # this error being raised means it's ok
    # other stuff

Des idées comment accomplir ceci?

Merci pour toute aide :)

101
Gerard

Cela devrait fonctionner pour votre cas.

assert not my_var.called, 'method should not have been called'

Échantillon;

>>> mock=Mock()
>>> mock.a()
<Mock name='mock.a()' id='4349129872'>
>>> assert not mock.b.called, 'b was called and should not have been'
>>> assert not mock.a.called, 'a was called and should not have been'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: a was called and should not have been
118
Joachim Isaksson

Bien qu’une vieille question, j’aimerais ajouter que la bibliothèque actuellement mock (portage de unittest.mock) prend en charge la méthode assert_not_called.

Juste améliorer le vôtre;

pip install mock --upgrade

42
Ahmet

Vous pouvez vérifier l'attribut called, mais si votre assertion échoue, la prochaine chose que vous voudrez savoir, c'est quelque chose de à propos de l'appel inattendu. Vous pouvez donc également organiser l'affichage de ces informations dès le début. En utilisant unittest, vous pouvez vérifier le contenu de call_args_list à la place:

self.assertItemsEqual(my_var.call_args_list, [])

Quand cela échoue, cela donne un message comme ceci:

 AssertionError: le nombre d'éléments n'était pas égal: 
 Le premier a 0, le second a 1: call ('premier argument', 4) 
27
Rob Kennedy

Lorsque vous testez en utilisant class hérite de unittest.TestCase, vous pouvez simplement utiliser des méthodes telles que:

  • affirmer vrai
  • affirmer
  • assertEqual

et similaire (dans documentation python vous trouvez le reste).

Dans votre exemple, nous pouvons simplement affirmer que la propriété mock_method.called est False, ce qui signifie que cette méthode n'a pas été appelée.

import unittest
from unittest import mock

import my_module

class A(unittest.TestCase):
    def setUp(self):
        self.message = "Method should not be called. Called {times} times!"

    @mock.patch("my_module.method_to_mock")
    def test(self, mock_method):
        my_module.method_to_mock()

        self.assertFalse(mock_method.called,
                         self.message.format(times=mock_method.call_count))
11
Hunter_71

À en juger par d’autres réponses, personne à l’exception de @ rob-kennedy n’a parlé du call_args_list.

C'est un outil puissant pour que vous puissiez implémenter l'exact contraire de MagicMock.assert_called_with()

call_args_list est une liste d'objets call. Chaque objet call représente un appel effectué sur un appelable simulé.

>>> from unittest.mock import MagicMock
>>> m = MagicMock()
>>> m.call_args_list
[]
>>> m(42)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42)]
>>> m(42, 30)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42), call(42, 30)]

Consommer un objet call est facile, car vous pouvez le comparer à un tuple de longueur 2 où le premier composant est un tuple contenant tous les arguments de position de l'appel associé, tandis que le second composant est un dictionnaire des arguments de mots clés.

>>> ((42,),) in m.call_args_list
True
>>> m(42, foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((42,), {'foo': 'bar'}) in m.call_args_list
True
>>> m(foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((), {'foo': 'bar'}) in m.call_args_list
True

Ainsi, un moyen de résoudre le problème spécifique du PO consiste à:

def test_something():
    with patch('something') as my_var:
        assert ((some, args),) not in my_var.call_args_list

Notez que de cette façon, au lieu de simplement vérifier si un appelable simulé a été appelé, via MagicMock.called, vous pouvez maintenant vérifier si elle a été appelée avec un jeu d’arguments spécifique.

C'est utile. Supposons que vous souhaitiez tester une fonction prenant une liste et appeler une autre fonction, compute(), pour chacune des valeurs de la liste uniquement si elles satisfont à une condition spécifique.

Vous pouvez maintenant simuler compute et tester s'il a été appelé pour une valeur mais pas pour d'autres.

0
Giuseppe

Avec python >= 3.5, vous pouvez utiliser mock_object.assert_not_called().

0
valex