Je dois toujours regarder celui-ci encore et encore, alors voici ma réponse.
Affirmation de plusieurs appels de méthode sur différents objets de la même classe
Supposons que nous ayons une classe résistante (dont nous voulons nous moquer):
In [1]: class HeavyDuty(object):
...: def __init__(self):
...: import time
...: time.sleep(2) # <- Spends a lot of time here
...:
...: def do_work(self, arg1, arg2):
...: print("Called with %r and %r" % (arg1, arg2))
...:
voici du code qui utilise deux instances de la HeavyDuty
classe:
In [2]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(13, 17)
...: hd2 = HeavyDuty()
...: hd2.do_work(23, 29)
...:
Maintenant, voici un cas de test pour la heavy_work
fonction:
In [3]: from unittest.mock import patch, call
...: def test_heavy_work():
...: expected_calls = [call.do_work(13, 17),call.do_work(23, 29)]
...:
...: with patch('__main__.HeavyDuty') as MockHeavyDuty:
...: heavy_work()
...: MockHeavyDuty.return_value.assert_has_calls(expected_calls)
...:
Nous nous moquons de la HeavyDuty
classe avec MockHeavyDuty
. Pour affirmer les appels de méthode provenant de chaque HeavyDuty
instance, nous devons nous référer à MockHeavyDuty.return_value.assert_has_calls
, au lieu de MockHeavyDuty.assert_has_calls
. De plus, dans la liste des, expected_calls
nous devons spécifier le nom de la méthode pour laquelle nous souhaitons affirmer les appels. Donc, notre liste est faite d'appels à call.do_work
, plutôt que simplement call
.
L'exercice du cas de test nous montre qu'il est réussi:
In [4]: print(test_heavy_work())
None
Si nous modifions la heavy_work
fonction, le test échoue et produit un message d'erreur utile:
In [5]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(113, 117) # <- call args are different
...: hd2 = HeavyDuty()
...: hd2.do_work(123, 129) # <- call args are different
...:
In [6]: print(test_heavy_work())
---------------------------------------------------------------------------
(traceback omitted for clarity)
AssertionError: Calls not found.
Expected: [call.do_work(13, 17), call.do_work(23, 29)]
Actual: [call.do_work(113, 117), call.do_work(123, 129)]
Affirmer plusieurs appels à une fonction
Pour contraster avec ce qui précède, voici un exemple qui montre comment se moquer de plusieurs appels à une fonction:
In [7]: def work_function(arg1, arg2):
...: print("Called with args %r and %r" % (arg1, arg2))
In [8]: from unittest.mock import patch, call
...: def test_work_function():
...: expected_calls = [call(13, 17), call(23, 29)]
...: with patch('__main__.work_function') as mock_work_function:
...: work_function(13, 17)
...: work_function(23, 29)
...: mock_work_function.assert_has_calls(expected_calls)
...:
In [9]: print(test_work_function())
None
Il existe deux différences principales. Le premier est que lorsque nous nous moquons d'une fonction, nous configurons nos appels attendus en utilisant call
plutôt qu'en utilisant call.some_method
. La seconde est que nous appelons assert_has_calls
au mock_work_function
lieu de continuer mock_work_function.return_value
.