J'ai une méthode en python (2.7) qui fait foo, et abandonne après 5 minutes si foo n'a pas fonctionné.
def keep_trying(self):
timeout = 300 #empirically derived, appropriate timeout
end_time = time.time() + timeout
while (time.time() < end_time):
result = self.foo()
if (result == 'success'):
break
time.sleep(2)
else:
raise MyException('useful msg here')
Je connais certains résultats possibles de foo (), donc j'utilise mock pour truquer ces valeurs de retour. Le problème est que je ne veux pas que le test s'exécute 5 minutes avant de voir l'exception.
Existe-t-il un moyen de remplacer cette valeur locale de délai d'attente? J'aimerais que ce ne soit que quelques secondes pour que je puisse voir la boucle essayer plusieurs fois, puis abandonner et augmenter.
Ce qui suit ne fonctionne pas:
@patch.object(myClass.keep_trying, 'timeout')
@patch.object(myClass, 'foo')
def test_keep_trying(self, mock_foo, mock_timeout):
mock_foo.return_value = 'failed'
mock_timeout.return_value = 10 # raises AttributeError
mock_timeout = 10 # raises AttributeError
...
Plutôt que d'essayer de simuler la valeur si timeout
, vous voudrez simuler la valeur de retour de time.time()
.
par exemple.
@patch.object(time, 'time')
def test_keep_trying(self, mock_time):
mock_time.side_effect = iter([100, 200, 300, 400, 500, 600, 700, 800])
...
Maintenant, la première fois que time.time()
est appelée, vous obtiendrez la valeur 100, elle devrait donc expirer après quelques tours de votre boucle while. Vous pouvez également vous moquer de time.sleep
Et compter le nombre de fois qu'il est appelé pour vous assurer qu'une partie du code fonctionne correctement.
Une autre approche (qui n'est pas complètement orthogonale à celle ci-dessus) consiste à permettre à l'utilisateur de passer un mot clé de temporisation facultatif à la fonction:
def keep_trying(self, timeout=300):
...
Cela vous permet de spécifier le timeout que vous voulez dans les tests (et dans le futur code qui ne veut pas attendre 5 minutes ;-).
Vous ne pouvez pas vous moquer de la variable locale d'une fonction. Pour rendre votre code plus facile à tester, changez-le en, par exemple:
def keep_trying(self, timeout=300):
end_time = time.time() + timeout
# etc, as above
il devient donc trivial pour les tests de l'exécuter avec un délai d'attente plus court!