webentwicklung-frage-antwort-db.com.de

Feststellen, dass eine Funktion/Methode nicht mit Mock aufgerufen wurde

Ich benutze die Mock-Bibliothek, um meine Anwendung zu testen, möchte aber behaupten, dass eine Funktion nicht aufgerufen wurde. Scheindokumente sprechen über Methoden wie mock.assert_called_with und mock.assert_called_once_with, aber ich fand nichts wie mock.assert_not_called oder etwas, das überprüft werden sollte, wenn das Mock NICHT genannt wurde .

Ich könnte mit so etwas wie dem folgenden gehen, obwohl es weder cool noch Pythonic erscheint:

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

Irgendwelche Ideen, wie man das schafft?

Danke für jede Hilfe :)

101
Gerard

Dies sollte für Ihren Fall funktionieren.

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

Probe;

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

Obwohl es sich um eine alte Frage handelt, möchte ich hinzufügen, dass die derzeit mock-Bibliothek (Rückport von unittest.mock) die assert_not_called-Methode unterstützt.

Aktualisieren Sie einfach Ihre.

pip install mock --upgrade

42
Ahmet

Sie können das called-Attribut überprüfen, aber wenn Ihre Assertion fehlschlägt, sollten Sie als nächstes etwas about des unerwarteten Aufrufs wissen, so dass Sie diese Informationen auch von Anfang an anzeigen können . Mit unittest können Sie stattdessen den Inhalt von call_args_list überprüfen:

self.assertItemsEqual(my_var.call_args_list, [])

Wenn dies fehlschlägt, wird eine Meldung wie folgt angezeigt:

 AssertionError: Die Anzahl der Elemente war nicht gleich: 
 First hat 0, Second hat 1: call ('erstes Argument', 4) 
27
Rob Kennedy

Wenn Sie mit Klassenvererbungen unittest.TestCase testen, können Sie einfach folgende Methoden verwenden:

  • assertTrue
  • assertFalse
  • assertEqual

und ähnlich (in Python-Dokumentation finden Sie den Rest).

In Ihrem Beispiel können Sie einfach behaupten, dass mock_method.called property False ist, was bedeutet, dass die Methode nicht aufgerufen wurde.

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

Nach anderen Antworten zu urteilen, sprach niemand außer @ rob-kennedy über den call_args_list.

Es ist ein mächtiges Werkzeug, mit dem Sie das genaue Gegenteil von MagicMock.assert_called_with() implementieren können.

call_args_list ist eine Liste von call-Objekten. Jedes call-Objekt stellt einen Aufruf dar, der bei einem aufgerufenen, aufrufbaren Aufruf gemacht wurde.

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

Die Verwendung eines call-Objekts ist einfach, da Sie es mit einem Tupel der Länge 2 vergleichen können, bei dem die erste Komponente ein Tuple ist, der alle Positionsargumente des zugehörigen Aufrufs enthält, während die zweite Komponente ein Wörterbuch der Schlüsselwortargumente ist.

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

Eine Möglichkeit, das spezifische Problem des OP anzugehen, ist also

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

Beachten Sie, dass Sie auf diese Weise, anstatt nur zu prüfen, ob ein überstrittenes Aufrufbares mit MagicMock.called aufgerufen wurde, prüfen können, ob es mit einem bestimmten Satz von Argumenten aufgerufen wurde.

Das ist nützlich Angenommen, Sie möchten eine Funktion testen, die eine Liste aufnimmt, und eine andere Funktion, compute(), für jeden Wert der Liste aufrufen, wenn sie eine bestimmte Bedingung erfüllen.

Sie können jetzt compute nachahmen und testen, ob es für einen Wert aufgerufen wurde, für andere jedoch nicht.

0
Giuseppe

Mit python >= 3.5 können Sie mock_object.assert_not_called() verwenden.

0
valex